Salome HOME
Debug of CMake build procedure
[modules/gui.git] / src / SalomeApp / SalomeApp_IntSpinBox.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_IntSpinBox.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_IntSpinBox.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_IntSpinBox
47 */
48
49 /*!
50   \brief Constructor.
51
52   Constructs a spin box with 0 as minimum value and 99 as maximum value,
53   a step value of 1. The value is initially set to 0.
54
55   \param parent parent object
56 */
57 SalomeApp_IntSpinBox::SalomeApp_IntSpinBox( QWidget* parent )
58 : QtxIntSpinBox( parent ),
59   myDefaultValue( 0 ),
60   myAcceptNames( true ),
61   myShowTip( true )
62 {
63   connectSignalsAndSlots();
64 }
65
66 /*!
67   \brief Constructor.
68
69   Constructs a spin box with specified minimum, maximum and step value.
70   The value is initially set to the minimum value.
71
72   \param min spin box minimum possible value
73   \param max spin box maximum possible value
74   \param step spin box increment/decrement value
75   \param parent parent object
76   \param acceptNames if true, enables variable names in the spin box
77   \param showTip if true, makes the widget show a tooltip when invalid text is entered by the user
78 */
79 SalomeApp_IntSpinBox::SalomeApp_IntSpinBox( int min, 
80                                             int max, 
81                                             int step, 
82                                             QWidget* parent,
83                                             bool acceptNames,
84                                             bool showTip )
85 : QtxIntSpinBox( min, max, step, parent ),
86   myDefaultValue( 0 ),
87   myAcceptNames( acceptNames ),
88   myShowTip( showTip )
89 {
90   connectSignalsAndSlots();
91 }
92
93 /*!
94   \brief Destructor.
95 */
96 SalomeApp_IntSpinBox::~SalomeApp_IntSpinBox()
97 {
98 }
99
100
101 /*!
102   \brief Perform \a steps increment/decrement steps.
103   
104   Re-implemented to handle cases when Notebook variable
105   name is specified by the user as the widget text.  
106   Otherwise, simply calls the base implementation.
107
108   \param steps number of increment/decrement steps
109 */
110 void SalomeApp_IntSpinBox::stepBy( int steps )
111 {
112   QString str  = text();
113   QString pref = prefix();
114   QString suff = suffix();
115   
116   if ( pref.length() && str.startsWith( pref ) )
117     str = str.right( str.length() - pref.length() );
118   if ( suff.length() && str.endsWith( suff ) )
119     str = str.left( str.length() - suff.length() );
120   
121   QRegExp varNameMask( "([a-z]|[A-Z]|_).*" );
122   if ( varNameMask.exactMatch( str ) )
123     return;
124
125   QtxIntSpinBox::stepBy( steps );
126 }
127
128 /*!
129   \brief Connect signals and slots.
130 */
131 void SalomeApp_IntSpinBox::connectSignalsAndSlots()
132 {
133   connect( this, SIGNAL( editingFinished() ),
134            this, SLOT( onEditingFinished() ) );
135
136   connect( this, SIGNAL( valueChanged( const QString& ) ),
137            this, SLOT( onTextChanged( const QString& ) ) );
138
139   connect( lineEdit(), SIGNAL( textChanged( const QString& ) ),
140            this, SLOT( onTextChanged( const QString& ) ) );
141
142   connect( lineEdit(), SIGNAL( textChanged( const QString& )),
143            this, SIGNAL( textChanged( const QString& ) ) );
144 }
145
146 /*!
147   \brief This function is called when editing is finished.
148 */
149 void SalomeApp_IntSpinBox::onEditingFinished()
150 {
151   if( myTextValue.isNull() )
152     myTextValue = text();
153
154   setText( myTextValue );
155 }
156
157 /*!
158   \brief This function is called when value is changed.
159 */
160 void SalomeApp_IntSpinBox::onTextChanged( const QString& text )
161 {
162   myTextValue = text;
163
164   int value = 0;
165   if( isValid( text, value ) == Acceptable )
166     myCorrectValue = text;
167 }
168
169 /*!
170   \brief Interpret text entered by the user as a value.
171   \param text text entered by the user
172   \return mapped value
173   \sa textFromValue()
174 */
175 int SalomeApp_IntSpinBox::valueFromText( const QString& text ) const
176 {
177   int value = 0;
178   if( isValid( text, value ) == Acceptable )
179     return value;
180
181   return defaultValue();
182 }
183
184 /*!
185   \brief This function is used by the spin box whenever it needs to display
186   the given value.
187
188   \param val spin box value
189   \return text representation of the value
190   \sa valueFromText()
191 */
192 QString SalomeApp_IntSpinBox::textFromValue( int val ) const
193 {
194   return QtxIntSpinBox::textFromValue( val );
195 }
196
197 /*!
198   \brief This function is used to determine whether input is valid.
199   \param str currently entered value
200   \param pos cursor position in the string
201   \return validating operation result
202 */
203 QValidator::State SalomeApp_IntSpinBox::validate( QString& str, int& pos ) const
204 {
205   //return QValidator::Acceptable;
206   QValidator::State res = QValidator::Invalid;
207
208   // Considering the input text as a variable name
209   // Applying Python identifier syntax:
210   // either a string starting with a letter, or a string starting with
211   // an underscore followed by at least one alphanumeric character
212   if ( isAcceptNames() ){
213     QRegExp varNameMask( "(([a-z]|[A-Z])([a-z]|[A-Z]|[0-9]|_)*)|(_([a-z]|[A-Z]|[0-9])+([a-z]|[A-Z]|[0-9]|_)*)" );
214     if ( varNameMask.exactMatch( str ) )
215       res = QValidator::Acceptable;
216   
217     if ( res == QValidator::Invalid ){
218       varNameMask.setPattern( "_" );
219       if ( varNameMask.exactMatch( str ) )  
220         res = QValidator::Intermediate;
221     }
222   }
223   
224   // Trying to interpret the current input text as a numeric value
225   if ( res == QValidator::Invalid )
226     res = QtxIntSpinBox::validate( str, pos );  
227   
228   // Show tooltip in case of invalid manual input
229   if ( isShowTipOnValidate() && lineEdit()->hasFocus() ){
230     if ( res != QValidator::Acceptable ){ // san: do we need to warn the user in Intermediate state???
231       SalomeApp_IntSpinBox* that = const_cast<SalomeApp_IntSpinBox*>( this );
232       QPoint pos( size().width(), 0. );
233       QPoint globalPos = mapToGlobal( pos );
234       QString minVal = textFromValue( minimum() );
235       QString maxVal = textFromValue( maximum() );
236       
237       QString templ( isAcceptNames() ? tr( "VALID_RANGE_VAR_MSG" ) : tr( "VALID_RANGE_NOVAR_MSG" ) );      
238       QString msg( templ.arg( minVal ).arg( maxVal ) );
239       
240       // Add extra hints to the message (if any passed through dynamic properties)
241       QVariant propVal = property( "validity_tune_hint" );
242       if ( propVal.isValid() ){
243         QString extraInfo = propVal.toString();
244         if ( !extraInfo.isEmpty() ){
245           msg += "\n";
246           msg += extraInfo;
247         }
248       }
249   
250       QToolTip::showText( globalPos, 
251                           msg, 
252                           that );
253     }
254     else
255       QToolTip::hideText();
256   }
257       
258   return res;
259 }
260
261 /*!
262   \brief This function is used to determine whether input is valid.
263   \return validating operation result
264 */
265 bool SalomeApp_IntSpinBox::isValid( QString& msg, bool toCorrect )
266 {
267   int value;
268   State aState = isValid( text(), value );
269
270   if( aState != Acceptable )
271   {
272     if( toCorrect )
273     {
274       if( aState == Incompatible )
275         msg += tr( "ERR_INCOMPATIBLE_TYPE" ).arg( text() ) + "\n";
276       else if( aState == NoVariable )
277         msg += tr( "ERR_NO_VARIABLE" ).arg( text() ) + "\n";
278       else if( aState == Invalid )
279         msg += tr( "ERR_INVALID_VALUE" ) + "\n";
280
281       setText( myCorrectValue );
282     }
283     return false;
284   }
285
286   return true;
287 }
288
289 /*!
290   \brief This function is used to set a default value for this spinbox.
291   \param value default value
292 */
293 void SalomeApp_IntSpinBox::setDefaultValue( const int value )
294 {
295   myDefaultValue = value;
296 }
297
298 /*!
299   \brief This function is used to set a current value for this spinbox.
300   \param value current value
301 */
302 void SalomeApp_IntSpinBox::setValue( const int value )
303 {
304   QtxIntSpinBox::setValue( value );
305
306   myCorrectValue = QString::number( value );
307   myTextValue = myCorrectValue;
308 }
309
310 /*!
311   \brief This function is used to set a text for this spinbox.
312   \param value current value
313 */
314 void SalomeApp_IntSpinBox::setText( const QString& value )
315 {
316   lineEdit()->setText(value);
317 }
318
319 /*!
320   \brief This function is used to determine whether input is valid.
321   \return validating operation result
322 */
323 SalomeApp_IntSpinBox::State SalomeApp_IntSpinBox::isValid( const QString& text, int& value ) const
324 {
325   SearchState aSearchState = findVariable( text, value );
326   if( aSearchState == NotFound )
327   {
328     bool ok = false;
329     value = text.toInt( &ok );
330     if( !ok )
331     {
332       text.toDouble( &ok );
333       if( ok )
334         return Invalid;
335       return NoVariable;
336     }
337   }
338   else if( aSearchState == IncorrectType )
339     return Incompatible;
340
341   if( !checkRange( value ) )
342     return Invalid;
343
344   return Acceptable;
345 }
346
347 /*!
348   \brief This function return a default acceptable value (commonly, 0).
349   \return default acceptable value
350 */
351 int SalomeApp_IntSpinBox::defaultValue() const
352 {
353   if( minimum() > myDefaultValue || maximum() < myDefaultValue )
354     return minimum();
355
356   return myDefaultValue;
357 }
358
359 /*!
360   \brief This function is used to check that string value lies within predefined range.
361   \return check status
362 */
363 bool SalomeApp_IntSpinBox::checkRange( const int value ) const
364 {
365   return value >= minimum() && value <= maximum();
366 }
367
368 /*!
369   \brief This function is used to determine whether input is a variable name and to get its value.
370   \return status of search operation
371 */
372 SalomeApp_IntSpinBox::SearchState SalomeApp_IntSpinBox::findVariable( const QString& name, int& value ) const
373 {
374   value = 0;
375   if( SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() ) )
376   {
377     if( SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( app->activeStudy() ) )
378     {
379       _PTR(Study) studyDS = study->studyDS();
380
381       std::string aName = name.toStdString();
382       if( studyDS->IsVariable( aName ) )
383       {
384         if( studyDS->IsInteger( aName ) || studyDS->IsString( aName ) )
385         {
386           if( studyDS->IsString( aName ) )
387             {
388 #ifndef DISABLE_PYCONSOLE
389               PyConsole_Console* pyConsole = app->pythonConsole();
390               PyConsole_Interp* pyInterp = pyConsole->getInterp();
391               PyLockWrapper aLock = pyInterp->GetLockWrapper();
392               std::string command;
393               command  = "import salome_notebook ; ";
394               command += "salome_notebook.notebook.setAsInteger(\"";
395               command += aName;
396               command += "\")";
397               bool aResult;
398               aResult = pyInterp->run(command.c_str());
399               if(aResult)
400                 {
401                   return IncorrectType;
402                 }
403 #endif
404             }
405           value = studyDS->GetInteger( aName );
406           return Found;
407         }
408         return IncorrectType;
409       }
410     }
411   }
412   return NotFound;
413 }
414
415 /*!
416   \brief This function is called when the spinbox recieves key press event.
417 */
418 void SalomeApp_IntSpinBox::keyPressEvent( QKeyEvent* e )
419 {
420   if ( e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter )
421     QWidget::keyPressEvent( e );
422   else
423     QtxIntSpinBox::keyPressEvent( e );
424 }
425
426 /*!
427   \brief This function is called when the spinbox recieves show event.
428 */
429 void SalomeApp_IntSpinBox::showEvent( QShowEvent* )
430 {
431   setText( myTextValue );
432 }
433
434 /*!
435   \brief Enables or disables variable names in the spin box.
436          By default, variable names are enabled.
437   \param flag If true, variable names are enabled.
438 */
439 void SalomeApp_IntSpinBox::setAcceptNames( const bool flag )
440 {
441   myAcceptNames = flag;
442 }
443
444 /*!
445   \brief Returns true if the spin box accepts variable names.
446 */
447 bool SalomeApp_IntSpinBox::isAcceptNames() const
448 {
449   return myAcceptNames;
450 }
451
452 /*!
453   \brief Enables or disables  tooltips in case of invalid or intermediate-state input.
454          Tooltips are enabled by default.
455   \param flag If true, tooltips are enabled.
456 */
457 void SalomeApp_IntSpinBox::setShowTipOnValidate( const bool flag )
458 {
459   myShowTip = myShowTip;
460 }
461
462 /*!
463   \brief Returns true if tooltip should be shown in case of invalid or intermediate-state input.
464 */
465 bool SalomeApp_IntSpinBox::isShowTipOnValidate() const
466 {
467   return myShowTip;
468 }