Salome HOME
Debug of CMake build procedure
[modules/gui.git] / src / SalomeApp / SalomeApp_DoubleSpinBox.cxx
1 // Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // File:      SalomeApp_DoubleSpinBox.cxx
21 // Author:    Oleg UVAROV
22 //
23
24 #ifndef DISABLE_PYCONSOLE
25   #include <PyConsole_Interp.h> // this include must be first (see PyInterp_base.h)!
26   #include <PyConsole_Console.h>
27 #endif
28
29 #include "SalomeApp_DoubleSpinBox.h"
30 #include "SalomeApp_Application.h"
31 #include "SalomeApp_Study.h"
32
33 #include <SUIT_Session.h>
34
35 #include "SALOMEDSClient_ClientFactory.hxx" 
36 #include CORBA_SERVER_HEADER(SALOMEDS)
37
38 #include <QKeyEvent>
39 #include <QLineEdit>
40 #include <QToolTip>
41 #include <QRegExp>
42
43 #include <string>
44
45 /*!
46   \class SalomeApp_DoubleSpinBox
47 */
48
49 /*!
50   \brief Constructor.
51
52   Constructs a spin box with 0.0 as minimum value and 99.99 as maximum value,
53   a step value of 1.0 and a precision of 2 decimal places. 
54   The value is initially set to 0.00.
55
56   \param parent parent object
57 */
58 SalomeApp_DoubleSpinBox::SalomeApp_DoubleSpinBox( QWidget* parent )
59 : QtxDoubleSpinBox( parent ),
60   myDefaultValue( 0.0 ),
61   myIsRangeSet( false ),
62   myMinimum( 0.0 ),
63   myMaximum( 99.99 ),
64   myAcceptNames( true ),
65   myShowTip( true )
66 {
67   connectSignalsAndSlots();
68 }
69
70 /*!
71   \brief Constructor.
72
73   Constructs a spin box with specified minimum, maximum and step value.
74   The precision is set to 2 decimal places. 
75   The value is initially set to the minimum value.
76
77   \param min spin box minimum possible value
78   \param max spin box maximum possible value
79   \param step spin box increment/decrement value
80   \param parent parent object
81 */
82 SalomeApp_DoubleSpinBox::SalomeApp_DoubleSpinBox( double min, double max, double step, QWidget* parent )
83 : QtxDoubleSpinBox( min, max, step, parent ),
84   myDefaultValue( 0.0 ),
85   myIsRangeSet( false ),
86   myMinimum( min ),
87   myMaximum( max ),
88   myAcceptNames( true ),
89   myShowTip( true )
90 {
91   connectSignalsAndSlots();
92 }
93
94 /*!
95   \brief Constructor.
96
97   Constructs a spin box with specified minimum, maximum and step value.
98   The precision is set to 2 decimal places. 
99   The value is initially set to the minimum value.
100
101   \param min spin box minimum possible value
102   \param max spin box maximum possible value
103   \param step spin box increment/decrement value
104   \param parent parent object
105   \param acceptNames if true, enables variable names in the spin box
106   \param showTip if true, makes the widget show a tooltip when invalid text is entered by the user
107 */
108 SalomeApp_DoubleSpinBox::SalomeApp_DoubleSpinBox( double min, 
109                                                   double max, 
110                                                   double step, 
111                                                   int prec, 
112                                                   int dec, 
113                                                   QWidget* parent,
114                                                   bool acceptNames,
115                                                   bool showTip )
116 : QtxDoubleSpinBox( min, max, step, prec, dec, parent ),
117   myDefaultValue( 0.0 ),
118   myIsRangeSet( false ),
119   myMinimum( min ),
120   myMaximum( max ),
121   myAcceptNames( acceptNames ),
122   myShowTip( showTip )
123 {
124   connectSignalsAndSlots();
125 }
126
127 /*!
128   \brief Destructor.
129 */
130 SalomeApp_DoubleSpinBox::~SalomeApp_DoubleSpinBox()
131 {
132 }
133
134 /*!
135   \brief Perform \a steps increment/decrement steps.
136   
137   Re-implemented to handle cases when Notebook variable
138   name is specified by the user as the widget text.  
139   Otherwise, simply calls the base implementation.
140
141   \param steps number of increment/decrement steps
142 */
143 void SalomeApp_DoubleSpinBox::stepBy( int steps )
144 {
145   QString str  = text();
146   QString pref = prefix();
147   QString suff = suffix();
148   
149   if ( pref.length() && str.startsWith( pref ) )
150     str = str.right( str.length() - pref.length() );
151   if ( suff.length() && str.endsWith( suff ) )
152     str = str.left( str.length() - suff.length() );
153   
154   QRegExp varNameMask( "([a-z]|[A-Z]|_).*" );
155   if ( varNameMask.exactMatch( str ) )
156     return;
157
158   QtxDoubleSpinBox::stepBy( steps );
159 }
160
161 /*!
162   \brief Connect signals and slots.
163 */
164 void SalomeApp_DoubleSpinBox::connectSignalsAndSlots()
165 {
166   connect( this, SIGNAL( editingFinished() ),
167            this, SLOT( onEditingFinished() ) );
168
169   connect( this, SIGNAL( valueChanged( const QString& ) ),
170            this, SLOT( onTextChanged( const QString& ) ) );
171
172   connect( lineEdit(), SIGNAL( textChanged( const QString& ) ),
173            this, SLOT( onTextChanged( const QString& ) ) );
174
175   connect( lineEdit(), SIGNAL( textChanged( const QString& )),
176            this, SIGNAL( textChanged( const QString& ) ) );
177 }
178
179 /*!
180   \brief This function is called when editing is finished.
181 */
182 void SalomeApp_DoubleSpinBox::onEditingFinished()
183 {
184   if( myTextValue.isNull() )
185     myTextValue = text();
186
187   setText( myTextValue );
188 }
189
190 /*!
191   \brief This function is called when value is changed.
192 */
193 void SalomeApp_DoubleSpinBox::onTextChanged( const QString& text )
194 {
195   myTextValue = text;
196
197   double value = 0;
198   if( isValid( text, value ) == Acceptable )
199     myCorrectValue = text;
200 }
201
202 /*!
203   \brief Interpret text entered by the user as a value.
204   \param text text entered by the user
205   \return mapped value
206   \sa textFromValue()
207 */
208 double SalomeApp_DoubleSpinBox::valueFromText( const QString& text ) const
209 {
210   double value = 0;
211   if( isValid( text, value ) == Acceptable )
212     return value;
213
214   return defaultValue();
215 }
216
217 /*!
218   \brief This function is used by the spin box whenever it needs to display
219   the given value.
220
221   \param val spin box value
222   \return text representation of the value
223   \sa valueFromText()
224 */
225 QString SalomeApp_DoubleSpinBox::textFromValue( double val ) const
226 {
227   return QtxDoubleSpinBox::textFromValue( val );
228 }
229
230 /*!
231   \brief This function is used to determine whether input is valid.
232   \param str currently entered value
233   \param pos cursor position in the string
234   \return validating operation result
235 */
236 QValidator::State SalomeApp_DoubleSpinBox::validate( QString& str, int& pos ) const
237 {
238   QValidator::State res = QValidator::Invalid;
239
240   // Considering the input text as a variable name
241   // Applying Python identifier syntax:
242   // either a string starting with a letter, or a string starting with
243   // an underscore followed by at least one alphanumeric character
244   if ( isAcceptNames() ){
245     QRegExp varNameMask( "(([a-z]|[A-Z])([a-z]|[A-Z]|[0-9]|_)*)|(_([a-z]|[A-Z]|[0-9])+([a-z]|[A-Z]|[0-9]|_)*)" );
246     if ( varNameMask.exactMatch( str ) )
247       res = QValidator::Acceptable;
248   
249     if ( res == QValidator::Invalid ){
250       varNameMask.setPattern( "_" );
251       if ( varNameMask.exactMatch( str ) )  
252         res = QValidator::Intermediate;
253     }
254   }
255   
256   // Trying to interpret the current input text as a numeric value
257   if ( res == QValidator::Invalid )
258     res = QtxDoubleSpinBox::validate( str, pos );  
259   
260   // Show tooltip in case of invalid manual input
261   if ( isShowTipOnValidate() && lineEdit()->hasFocus() ){
262     if ( res != QValidator::Acceptable ){ // san: do we need to warn the user in Intermediate state???
263       SalomeApp_DoubleSpinBox* that = const_cast<SalomeApp_DoubleSpinBox*>( this );
264       QPoint pos( size().width(), 0. );
265       QPoint globalPos = mapToGlobal( pos );
266       QString minVal = textFromValue( minimum() );
267       QString maxVal = textFromValue( maximum() );
268       
269       // Same stuff as in QtxDoubleSpinBox::textFromValue()
270       int digits = getPrecision();
271       
272       // For 'g' format, max. number of digits after the decimal point is getPrecision() - 1
273       // See also QtxDoubleSpinBox::validate()
274       if ( digits < 0 )
275         digits = qAbs( digits ) - 1;
276       
277       QString templ( isAcceptNames() ? tr( "VALID_RANGE_VAR_MSG" ) : tr( "VALID_RANGE_NOVAR_MSG" ) );
278       QString msg( templ.arg( minVal ).arg( maxVal ).arg( digits ) );
279       
280       // Add extra hints to the message (if any passed through dynamic properties)
281       QVariant propVal = property( "validity_tune_hint" );
282       if ( propVal.isValid() ){
283         QString extraInfo = propVal.toString();
284         if ( !extraInfo.isEmpty() ){
285           msg += "\n";
286           msg += extraInfo;
287         }
288       }
289       
290       QToolTip::showText( globalPos, 
291                           msg, 
292                           that );
293     }
294     else
295       QToolTip::hideText();
296   }
297       
298   return res;
299 }
300
301 /*!
302   \brief This function is used to determine whether input is valid.
303   \return validating operation result
304 */
305 bool SalomeApp_DoubleSpinBox::isValid( QString& msg, bool toCorrect )
306 {
307   double value;
308   State aState = isValid( text(), value );
309
310   if( aState != Acceptable )
311   {
312     if( toCorrect )
313     {
314       if( aState == Incompatible )
315         msg += tr( "ERR_INCOMPATIBLE_TYPE" ).arg( text() ) + "\n";
316       else if( aState == NoVariable )
317         msg += tr( "ERR_NO_VARIABLE" ).arg( text() ) + "\n";
318       else if( aState == Invalid )
319         msg += tr( "ERR_INVALID_VALUE" ) + "\n";
320
321       setText( myCorrectValue );
322     }
323     return false;
324   }
325
326   return true;
327 }
328
329 /*!
330   \brief This function is used to set a default value for this spinbox.
331   \param value default value
332 */
333 void SalomeApp_DoubleSpinBox::setDefaultValue( const double value )
334 {
335   myDefaultValue = value;
336 }
337
338 /*!
339   \brief This function is used to set minimum and maximum values for this spinbox.
340   \param min minimum value
341   \param max maximum value
342 */
343 void SalomeApp_DoubleSpinBox::setRange( const double min, const double max )
344 {
345   QtxDoubleSpinBox::setRange( min, max );
346
347   myIsRangeSet = true;
348   myMinimum = min;
349   myMaximum = max;
350 }
351
352 /*!
353   \brief This function is used to set a current value for this spinbox.
354   \param value current value
355 */
356 void SalomeApp_DoubleSpinBox::setValue( const double value )
357 {
358   QtxDoubleSpinBox::setValue( value );
359
360   myCorrectValue = QtxDoubleSpinBox::textFromValue( value );
361   myTextValue = myCorrectValue;
362 }
363
364 /*!
365   \brief This function is used to set a text for this spinbox.
366   \param value current value
367 */
368 void SalomeApp_DoubleSpinBox::setText( const QString& value )
369 {
370   lineEdit()->setText(value);
371 }
372
373 /*!
374   \brief This function is used to determine whether input is valid.
375   \return validating operation result
376 */
377 SalomeApp_DoubleSpinBox::State SalomeApp_DoubleSpinBox::isValid( const QString& text, double& value ) const
378 {
379   SearchState aSearchState = findVariable( text, value );
380   if( aSearchState == NotFound )
381   {
382     bool ok = false;
383     value = locale().toDouble( text, &ok );
384     if ( !ok )
385       return NoVariable;
386   }
387   else if( aSearchState == IncorrectType )
388     return Incompatible;
389
390   if( !checkRange( value ) )
391     return Invalid;
392
393   return Acceptable;
394 }
395
396 /*!
397   \brief This function return a default acceptable value (commonly, 0.0).
398   \return default acceptable value
399 */
400 double SalomeApp_DoubleSpinBox::defaultValue() const
401 {
402   if( myMinimum > myDefaultValue || myMaximum < myDefaultValue )
403     return myMinimum;
404
405   return myDefaultValue;
406 }
407
408 /*!
409   \brief This function is used to check that string value lies within predefined range.
410   \return check status
411 */
412 bool SalomeApp_DoubleSpinBox::checkRange( const double value ) const
413 {
414   if( !myIsRangeSet )
415     return true;
416
417   return value >= myMinimum && value <= myMaximum;
418 }
419
420 /*!
421   \brief This function is used to determine whether input is a variable name and to get its value.
422   \return status of search operation
423 */
424 SalomeApp_DoubleSpinBox::SearchState SalomeApp_DoubleSpinBox::findVariable( const QString& name, double& value ) const
425 {
426   value = 0;
427   if( SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() ) )
428   {
429     if( SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
430     {
431       _PTR(Study) studyDS = study->studyDS();
432
433       std::string aName = name.toStdString();
434       if( studyDS->IsVariable( aName ) )
435       {
436         if( studyDS->IsReal( aName ) || studyDS->IsInteger( aName ) || studyDS->IsString( aName ) )
437         {
438           if( studyDS->IsString( aName ) )
439             {
440 #ifndef DISABLE_PYCONSOLE
441               PyConsole_Console* pyConsole = app->pythonConsole();
442               PyConsole_Interp* pyInterp = pyConsole->getInterp();
443               PyLockWrapper aLock = pyInterp->GetLockWrapper();
444               std::string command;
445               command  = "import salome_notebook ; ";
446               command += "salome_notebook.notebook.setAsReal(\"";
447               command += aName;
448               command += "\")";
449               bool aResult;
450               aResult = pyInterp->run(command.c_str());
451               if(aResult)
452                 {
453                   return IncorrectType;
454                 }
455 #endif
456             }
457           value = studyDS->GetReal( aName );
458           return Found;
459         }
460         return IncorrectType;
461       }
462     }
463   }
464   return NotFound;
465 }
466
467 /*!
468   \brief This function is called when the spinbox recieves key press event.
469 */
470 void SalomeApp_DoubleSpinBox::keyPressEvent( QKeyEvent* e )
471 {
472   if ( e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter )
473     QWidget::keyPressEvent( e );
474   else
475     QtxDoubleSpinBox::keyPressEvent( e );
476 }
477
478 /*!
479   \brief This function is called when the spinbox recieves show event.
480 */
481 void SalomeApp_DoubleSpinBox::showEvent( QShowEvent* )
482 {
483   setText( myTextValue );
484 }
485
486 /*!
487   \brief Enables or disables variable names in the spin box.
488          By default, variable names are enabled.
489   \param flag If true, variable names are enabled.
490 */
491 void SalomeApp_DoubleSpinBox::setAcceptNames( const bool flag )
492 {
493   myAcceptNames = flag;
494 }
495
496 /*!
497   \brief Returns true if the spin box accepts variable names.
498 */
499 bool SalomeApp_DoubleSpinBox::isAcceptNames() const
500 {
501   return myAcceptNames;
502 }
503
504 /*!
505   \brief Enables or disables  tooltips in case of invalid or intermediate-state input.
506          Tooltips are enabled by default.
507   \param flag If true, tooltips are enabled.
508 */
509 void SalomeApp_DoubleSpinBox::setShowTipOnValidate( const bool flag )
510 {
511   myShowTip = myShowTip;
512 }
513
514 /*!
515   \brief Returns true if tooltip should be shown in case of invalid or intermediate-state input.
516 */
517 bool SalomeApp_DoubleSpinBox::isShowTipOnValidate() const
518 {
519   return myShowTip;
520 }