Salome HOME
Join modifications from BR_Dev_For_4_0 tag V4_1_1.
[modules/gui.git] / src / QDS / QDS_Datum.cxx
1 // Copyright (C) 2005  CEA/DEN, EDF R&D, OPEN CASCADE, PRINCIPIA R&D
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.
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 #include "QDS_Datum.h"
20
21 #include "QDS_Validator.h"
22
23 #include <DDS_Dictionary.h>
24
25 #include <qtimer.h>
26 #include <qlabel.h>
27 #include <qwidget.h>
28 #include <qlayout.h>
29 #include <qtooltip.h>
30 #include <qwhatsthis.h>
31 #include <qvalidator.h>
32 #include <qmessagebox.h>
33
34 #include <TColStd_SequenceOfAsciiString.hxx>
35
36 /*!
37   class: QDS_Datum::Wrapper
38   descr: Wrapper widget for sub widgets. [internal]
39 */
40
41 class QDS_Datum::Wrapper : public QWidget
42 {
43 public:
44   Wrapper( QWidget* = 0 );
45   virtual ~Wrapper();
46
47   QWidget*      widget() const;
48   void          setWidget( QWidget* );
49
50   virtual void  setGeometry( int x, int y, int w, int h );
51   virtual void  setSizePolicy( QSizePolicy );
52
53 private:
54   QWidget*      myWid;
55 };
56
57 QDS_Datum::Wrapper::Wrapper( QWidget* parent )
58 : QWidget( parent ),
59 myWid( 0 )
60 {
61   QHBoxLayout* base = new QHBoxLayout( this );
62   base->setAutoAdd( true );
63   setFocusPolicy( StrongFocus );
64 }
65
66 QDS_Datum::Wrapper::~Wrapper()
67 {
68 }
69
70 QWidget* QDS_Datum::Wrapper::widget() const
71 {
72   return myWid;
73 }
74
75 void QDS_Datum::Wrapper::setWidget( QWidget* wid )
76 {
77   if ( myWid == wid )
78     return;
79
80   myWid = wid;
81
82   if ( !myWid )
83     return;
84
85   if ( myWid->parent() != this )
86     myWid->reparent( this, QPoint( 0, 0 ) );
87
88   setTabOrder( this, myWid );
89   setFocusProxy( myWid );
90
91   myWid->updateGeometry();
92   updateGeometry();
93 }
94
95 void QDS_Datum::Wrapper::setSizePolicy( QSizePolicy sp )
96 {
97   QWidget::setSizePolicy( sp );
98
99   if ( widget() )
100     widget()->setSizePolicy( sp );
101 }
102
103 void QDS_Datum::Wrapper::setGeometry( int x, int y, int w, int h )
104 {
105   QWidget::setGeometry( x, y, w, h );
106
107   if ( widget() && widget()->size() != size() )
108     widget()->setGeometry( 0, 0, width(), height() );
109 }
110
111 /*!
112   \class QDS_Datum
113
114   This is a base class for control using the data dictionary. Datum is successor of QObject (not QWidget).
115   This object can have three sub widgets named as Label, Control and Units. User can skip creation of
116   some of them manipulate by parameter \aflags. Label widget display label of datum, Control widget allow
117   to input value, Units widget display units of measure in the active system.
118   
119   These widgets constructs under parent of datum. If this parent has layout which can automaticaly add child
120   widgets (see QLayout::setAutoAdd()) then these subwidgets will be placed in following order: first widget
121   is Label, second - Control, third - Unints. User can add these widgets to layout manually using methods
122   QDS_Datum::addTo() or QDS_Datum::widget(). In last case User can retrieve desired widget and place it into
123   layout.
124
125   If use QGroupBox as parent widget for datum object then all subwidgets will be arranged automatically by
126   group box according to column and orientation properties of QGroupBox.
127
128   For example:
129     QGroupBox* box = new QGroupBox( 3, Qt::Horizontal, "datum box" );
130     QDS_Datum* d1  = new QDS_Datum( "datum_1", box, All );
131     QDS_Datum* d2  = new QDS_Datum( "datum_2", box, All );
132     QDS_Datum* d3  = new QDS_Datum( "datum_3", box, All );
133
134   In this example we create the QGroupBox with 3 horizontal columns. All created datum widgets will be
135   placed automatically three widgets in a row. Each datum will be placed from up to bottom one by one.
136
137   Datum value is stored as string. User can get/set this value in different kinds:
138     \liAs string  - methods stringValue()/setStringValue().
139     \liAs integer - methods integerValue()/setIntegerValue(). Given value converted to/from SI.
140     \liAs double  - methods doubleValue()/setDoubleValue(). Given value converted to/from SI.
141     \liAs variant - methods value()/setValue().
142
143   User can perform some actions on datum subwidgets using following methods: isEnabled(),
144   setEnabled(), show(), hide(), setShown(), setFocus(), setAlignment().
145 */
146
147 /*!
148   Constructor. Create datum object with datum identifier \aid under widget \aparent. Parameter \aflags
149   define behaviour of datum and set of created subwidgets. Default value of this parameter is QDS::All.
150   Parameter \acomp specify the component name which will be used during search of dictionary item.
151
152   Datum register self in the static list by QDS::insertDatum().
153 */
154 QDS_Datum::QDS_Datum( const QString& id, QWidget* parent, const int flags, const QString& comp )
155 : QObject( parent ),
156 myId( id ),
157 myLabel( 0 ),
158 myUnits( 0 ),
159 myControl( 0 ),
160 myFlags( flags ),
161 myInitialised( false )
162 {
163   if ( myFlags & Label )
164     myWrapper.insert( Label, new Wrapper( parent ) );
165   if ( myFlags & Control )
166     myWrapper.insert( Control, new Wrapper( parent ) );
167   if ( myFlags & Units )
168     myWrapper.insert( Units, new Wrapper( parent ) );
169
170   for ( QMap<int, Wrapper*>::Iterator it = myWrapper.begin(); it != myWrapper.end(); ++it )
171     connect( it.data(), SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
172
173   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
174   if ( aDict.IsNull() )
175     return;
176
177   TCollection_AsciiString anId = toAsciiString( id );
178   TCollection_AsciiString aComp = toAsciiString( comp );
179
180   if ( aComp.IsEmpty() )
181     setDicItem( aDict->GetDicItem( anId ) );
182   else
183     setDicItem( aDict->GetDicItem( anId, aComp ) );
184
185   QTimer::singleShot( 0, this, SLOT( onInitDatum() ) );
186
187   if ( parent )
188     parent->installEventFilter( this );
189
190   insertDatum( this );
191 }
192
193 /*!
194   Destructor. Destroy all subwidget.
195   Datum unregister self from the static list by QDS::removeDatum().
196 */
197 QDS_Datum::~QDS_Datum()
198 {
199   removeDatum( this );
200
201   delete myLabel;
202   delete myUnits;
203   delete myControl;
204 /*
205   for ( QMap<int, Wrapper*>::Iterator it = myWrapper.begin(); it != myWrapper.end(); ++it )
206     delete it.data();
207 */
208 }
209
210 /*!
211   Overloaded operator allow to retrieve main subwidget named Control.
212 */
213 QDS_Datum::operator QWidget*() const
214 {
215   return widget( Control );
216 }
217
218 /*!
219   Returns the datum id.
220 */
221 QString QDS_Datum::id() const
222 {
223   initDatum();
224
225   return myId;
226 }
227
228 /*!
229   Returns the datum type of value.
230 */
231 int QDS_Datum::type() const
232 {
233   initDatum();
234
235   int res = DDS_DicItem::Unknown;
236   if ( !myDicItem.IsNull() )
237     res = myDicItem->GetType();
238   return res;
239 }
240
241 /*!
242   Returns the datum label string.
243 */
244 QString QDS_Datum::label() const
245 {
246   initDatum();
247
248   QString labStr;
249   if ( !myDicItem.IsNull() )
250     labStr = toQString( myDicItem->GetLabel() );
251
252   if ( flags() & NotAccel )
253     labStr = removeAccel( labStr );
254
255   return labStr;
256 }
257
258 /*!
259   Returns the datum units string.
260 */
261 QString QDS_Datum::units() const
262 {
263   initDatum();
264
265   QString unitStr;
266   if ( !myDicItem.IsNull() )
267     unitStr = toQString( myDicItem->GetUnits() );
268   return unitStr;
269 }
270
271 /*!
272   Returns the datum value filter string.
273 */
274 QString QDS_Datum::filter() const
275 {
276   initDatum();
277
278   QString fltr;
279   if ( !myDicItem.IsNull() )
280     fltr = toQString( myDicItem->GetFilter() );
281   return fltr;
282 }
283
284 /*!
285   Returns the datum value format string.
286 */
287 QString QDS_Datum::format() const
288 {
289   initDatum();
290
291   QString fmtStr;
292   if ( !myDicItem.IsNull() )
293     fmtStr = toQString( myDicItem->GetFormat( false ) );
294   return fmtStr;
295 }
296
297 /*!
298   Returns the datum default value string.
299 */
300 QString QDS_Datum::defaultValue() const
301 {
302   initDatum();
303
304   QString pref = prefix();
305   QString suff = suffix();
306
307   QString def;
308   if ( !myDicItem.IsNull() )
309     def = toQString( myDicItem->GetDefaultValue() );
310
311   QString aDef = def.stripWhiteSpace();
312   if ( !pref.isEmpty() && aDef.left( pref.length() ) == pref )
313     aDef = aDef.mid( pref.length() );
314
315   if ( !suff.isEmpty() && aDef.right( suff.length() ) == suff )
316     aDef = aDef.mid( 0, aDef.length() - suff.length() );
317
318   return aDef;
319 }
320
321 /*!
322   Returns the datum minimum value string.
323 */
324 QString QDS_Datum::minimumValue() const
325 {
326   initDatum();
327
328   QString min;
329   if ( !myDicItem.IsNull() && myDicItem->HasData( DDS_DicItem::MinValue ) )
330       min = format( format(), type(), myDicItem->GetMinValue() );
331   return min;
332 }
333
334 /*!
335   Returns the datum maximum value string.
336 */
337 QString QDS_Datum::maximumValue() const
338 {
339   initDatum();
340
341   QString max;
342   if ( !myDicItem.IsNull() && myDicItem->HasData( DDS_DicItem::MaxValue ) )
343     max = format( format(), type(), myDicItem->GetMaxValue() );
344   return max;
345 }
346
347 /*!
348   Returns the datum long description.
349 */
350 QString QDS_Datum::longDescription() const
351 {
352   initDatum();
353
354   QString ldStr;
355   if ( !myDicItem.IsNull() )
356     ldStr = toQString( myDicItem->GetLongDescription() );
357   return ldStr;
358 }
359
360 /*!
361   Returns the datum short description.
362 */
363 QString QDS_Datum::shortDescription() const
364 {
365   initDatum();
366
367   QString sdStr;
368   if ( !myDicItem.IsNull() )
369     sdStr = toQString( myDicItem->GetLongDescription() );
370   return sdStr;
371 }
372
373 /*!
374   Returns the list of option names.
375 */
376 QStringList QDS_Datum::options() const
377 {
378   QStringList res;
379   if ( !dicItem().IsNull() )
380   {
381     TColStd_SequenceOfAsciiString lst;
382     dicItem()->GetOptionNames( lst );
383     for ( int i = 1; i <= lst.Length(); i++ )
384       res.append( toQString( lst.Value( i ) ) );
385   }
386   return res;
387 }
388
389 /*!
390   Returns the option specified by \aname as QVariant.
391   If option not exist then not valid QVariant returned.
392 */
393 QVariant QDS_Datum::option( const QString& name ) const
394 {
395   QVariant res;
396   if ( !dicItem().IsNull() )
397     res = QVariant( toQString( dicItem()->GetOption( toAsciiString( name ) ) ) );
398   return res;
399 }
400
401 /*!
402   Returns the option specified by \aname as QString.
403   If option not exist then empty string returned.
404 */
405 QString QDS_Datum::optionString( const QString& name ) const
406 {
407   QString res;
408   if ( !dicItem().IsNull() )
409     res = toQString( dicItem()->GetOption( toAsciiString( name ) ) );
410   return res;
411 }
412
413 /*!
414   Returns the option specified by \aname as double.
415   If option not exist then 0 returned.
416 */
417 double QDS_Datum::optionDouble( const QString& name ) const
418 {
419   double res = 0;
420   QVariant opt = option( name );
421   if ( opt.isValid() && opt.canCast( QVariant::Double ) )
422     res = opt.toDouble();
423   return res;
424 }
425
426 /*!
427   Returns the option specified by \aname as integer.
428   If option not exist then 0 returned.
429 */
430 int QDS_Datum::optionInteger( const QString& name ) const
431 {
432   int res = 0;
433   QVariant opt = option( name );
434   if ( opt.isValid() && opt.canCast( QVariant::Int ) )
435     res = opt.toInt();
436   return res;
437 }
438
439 /*!
440   Returns the datum value as variant (QVariant object).
441 */
442 QVariant QDS_Datum::value() const
443 {
444   QVariant val;
445   if ( !isEmpty() )
446     val = stringValue();
447   return val;
448 }
449
450 /*!
451   Returns the datum value as string (QString object).
452 */
453 QString QDS_Datum::stringValue() const
454 {
455   initDatum();
456
457   if ( getString() == myTargetValue )
458     return mySourceValue;
459   else
460     return getString();
461 }
462
463 /*!
464   Returns the datum value as double. This value converted from units of measure in active unit system
465   to units of measure in unit system "SI".
466 */
467 double QDS_Datum::doubleValue() const
468 {
469   initDatum();
470
471   double res = 0;
472   if ( !myTargetValue.isNull() && myTargetValue == getString() )
473     res = mySourceValue.toDouble();
474   else
475   {
476     res = getString().toDouble();
477     if ( !myDicItem.IsNull() )
478       res = myDicItem->ToSI( res );
479   }
480
481   return res;
482 }
483
484 /*!
485   Returns the datum value as integer. This value converted from units of measure in active unit system
486   to units of measure in unit system "SI".
487 */
488 int QDS_Datum::integerValue() const
489 {
490   initDatum();
491
492   int res = 0;
493   if ( !myTargetValue.isNull() && myTargetValue == getString() )
494     res = mySourceValue.toInt();
495   else
496   {
497     double val = getString().toDouble();
498     if ( !myDicItem.IsNull() )
499       res = (int)myDicItem->ToSI( val );
500   }
501
502   return res;
503 }
504
505 /*!
506   Returns the text from datum. Text consist of label, string value and units.
507 */
508 QString QDS_Datum::text() const
509 {
510   initDatum();
511
512   QString aLabel = label();
513   QString aData  = stringValue();
514   QString aUnits = units();
515
516   QString res = aLabel;
517   if ( !res.isEmpty() && !aData.isEmpty() )
518     res += QString( ": " );
519
520   res += aData;
521   if ( !aUnits.isEmpty() )
522     res += QString( " " ) + aUnits;
523
524   return res;
525 }
526
527 /*!
528   Returns false if datum control has inputted value.
529 */
530 bool QDS_Datum::isEmpty() const
531 {
532   return stringValue().isEmpty();
533 }
534
535 /*!
536   Reset datum state and set default value as current.
537 */
538 void QDS_Datum::reset()
539 {
540   initDatum();
541
542   mySourceValue = defaultValue();
543   setString( format( ( myFlags & NotFormat ) ? (QString) "" : format(), type(), mySourceValue ) );
544   invalidateCache();
545
546   onParamChanged();
547   QString str = getString();
548   emit paramChanged();
549   emit paramChanged( str );
550 }
551
552 /*!
553   Clear the control.
554 */
555 void QDS_Datum::clear()
556 {
557   initDatum();
558
559   if ( !getString().isEmpty() )
560   {
561     mySourceValue = "";
562     setString( mySourceValue );
563     invalidateCache();
564
565     onParamChanged();
566     QString str = getString();
567     emit paramChanged();
568     emit paramChanged( str );
569   }
570 }
571
572 /*!
573   Set varian value (QVariant object) into datum.
574 */
575 void QDS_Datum::setValue( const QVariant& val )
576 {
577   if ( val.isValid() && val.canCast( QVariant::String ) )
578     setStringValue( val.toString() );
579   else
580     clear();
581 }
582
583 /*!
584   Set string value (QString object) into datum.
585 */
586 void QDS_Datum::setStringValue( const QString& txt )
587 {
588   initDatum();
589
590   mySourceValue = txt;
591   QString aStr = format( ( flags() & NotFormat ) ? (QString) "" : format(), type(), txt );
592   setString( aStr );
593   myTargetValue = aStr;
594
595   onParamChanged();
596   QString str = getString();
597   emit paramChanged();
598   emit paramChanged( str );
599 }
600
601 /*!
602   Set double value into datum. This value converted from units of measure in unit system "SI"
603   to units of measure in active unit system. Format the value using datum format if it required.
604 */
605 void QDS_Datum::setDoubleValue( const double num )
606 {
607   initDatum();
608
609   mySourceValue = QString().setNum( num, 'g', 16 );
610   double val = num;
611   if ( !myDicItem.IsNull() )
612     val = myDicItem->FromSI( val );
613
614   QString aStr = format( ( flags() & NotFormat ) ? (QString) "" : format(), type(), val );
615   setString( aStr );
616   myTargetValue = aStr;
617
618   onParamChanged();
619   QString str = getString();
620   emit paramChanged();
621   emit paramChanged( str );
622 }
623
624 /*!
625   Set integer value into datum. This value converted from units of measure in unit system "SI"
626   to units of measure in active unit system. Format the value using datum format if it required.
627 */
628 void QDS_Datum::setIntegerValue( const int num )
629 {
630   initDatum();
631
632   mySourceValue = QString().setNum( num );
633   double val = num;
634   if ( !myDicItem.IsNull() )
635     val = myDicItem->FromSI( val );
636
637   QString aStr = format( ( flags() & NotFormat ) ? (QString) "" : format(), type(), val );
638   setString( aStr );
639   myTargetValue = aStr;
640
641   onParamChanged();
642   QString str = getString();
643   emit paramChanged();
644   emit paramChanged( str );
645 }
646
647 /*!
648   Returns true if all subwidgets specified by \aelement enabled.
649 */
650 bool QDS_Datum::isEnabled( const int element ) const
651 {
652   initDatum();
653
654   bool res = true;
655   if ( element & Label )
656     res = res && labelWidget() && labelWidget()->isEnabled();
657   if ( element & Units )
658     res = res && unitsWidget() && unitsWidget()->isEnabled();
659   if ( element & Control )
660     res = res && controlWidget() && controlWidget()->isEnabled();
661   return res;
662 }
663
664 /*!
665   Enable/Disable subwidgets specified by \aelement.
666   Possible values of \aelement: Label, Control, Units or their combinations.
667 */
668 void QDS_Datum::setEnabled( const bool on, const int element )
669 {
670   initDatum();
671
672   if ( element & Label && labelWidget() )
673     labelWidget()->setEnabled( on );
674   if ( element & Units && unitsWidget() )
675     unitsWidget()->setEnabled( on );
676   if ( element & Control && controlWidget() )
677     controlWidget()->setEnabled( on );
678 }
679
680 /*!
681   Enable/Disable control.
682 */
683 void QDS_Datum::setEnabled( bool on )
684 {
685   setEnabled( on, Control );
686 }
687
688 /*!
689   Show/hide subwidgets specified by \aelement.
690   Possible values of \aelement: Label, Control, Units or their combinations.
691 */
692 void QDS_Datum::setShown( const bool visible, const int flags )
693 {
694   initDatum();
695
696   uint flag = Units;
697   while ( flag )
698   {
699     if ( flags & flag && widget( flag ) )
700       widget( flag )->setShown( visible );
701     flag = flag >> 1;
702   }
703 }
704
705 /*!
706   Show subwidgets specified by \aelement.
707   Possible values of \aelement: Label, Control, Units or their combinations.
708 */
709 void QDS_Datum::show( const int element )
710 {
711   setShown( true, element );
712 }
713
714 /*!
715   Hide subwidgets specified by \aelement.
716   Possible values of \aelement: Label, Control, Units or their combinations.
717 */
718 void QDS_Datum::hide( const int element )
719 {
720   setShown( false, element );
721 }
722
723 /*!
724   Returns subwidget specified by \aelement.
725   Possible values of \aelement: Label, Control, Units.
726 */
727 QWidget* QDS_Datum::widget( const int element ) const
728 {
729   initDatum();
730   return wrapper( element );
731 }
732
733 /*!
734   Set the input focus on the control widget.
735 */
736 void QDS_Datum::setFocus()
737 {
738   initDatum();
739
740   if ( controlWidget() )
741     controlWidget()->setFocus();
742 }
743
744 /*!
745   Returns true if control contains valid value otherwise returns false
746   and display warning message box if parameter \amsgBox is set.
747 */
748 bool QDS_Datum::isValid( const bool msgBox, const QString& extMsg, const QString& extLabel ) const
749 {
750   initDatum();
751
752   if ( type() == DDS_DicItem::String && isDoubleFormat( format() ) )
753     return true;
754
755   QString req;
756   if ( !dicItem().IsNull() )
757     req = toQString( dicItem()->GetRequired() );
758
759   bool aState = true;
760   QString aStr = getString();
761
762   if ( aStr.isEmpty() )
763     aState = !( req == QString( "yes" ) || req == QString( "true" ) || req.toInt() );
764   else
765     aState = validate( aStr );
766
767   if ( msgBox && !aState )
768   {
769     QString info;
770     if ( !label().isEmpty() )
771       info += tr( "DATA_INCORRECT_VALUE" ).arg( label() );
772     else if ( !extLabel.isEmpty() )
773       info += tr( "DATA_INCORRECT_VALUE" ).arg( extLabel );
774
775     QString typeStr;
776     switch ( type() )
777     {
778     case DDS_DicItem::String:
779       typeStr = tr( "DATA_STRING" );
780       break;
781     case DDS_DicItem::Integer:
782       typeStr = tr( "DATA_INTEGER" );
783       break;
784     case DDS_DicItem::Float:
785       typeStr = tr( "DATA_FLOAT" );
786       break;
787     default:
788       typeStr = tr( "DATA_NON_EMPTY" );
789       break;
790     }
791     info += ( info.isEmpty() ? (QString) "" : QString( "\n" ) ) + 
792             tr( "DATA_SHOULD_BE_VALUE" ).arg( typeStr );
793     QString limit;
794     if ( type() == DDS_DicItem::Float || type() == DDS_DicItem::Integer )
795     {
796       QString aMinValue = minValue();
797       QString aMaxValue = maxValue();
798       if ( !aMinValue.isEmpty() && !aMaxValue.isEmpty() )
799         limit = tr( "DATA_RANGE" ).arg( aMinValue ).arg( aMaxValue );
800       else if ( !aMinValue.isEmpty() )
801         limit = tr( "DATA_MIN_LIMIT" ).arg( aMinValue );
802       else if ( !aMaxValue.isEmpty() )
803         limit = tr( "DATA_MAX_LIMIT" ).arg( aMaxValue );
804     }
805     if ( !limit.isEmpty() )
806       info += limit;
807
808     info += QString( ".\n" ) + tr( "DATA_INPUT_VALUE" );
809
810     if ( !extMsg.isEmpty() )
811       info += QString( "\n" ) + extMsg;
812
813     QString msg;
814     for ( uint i = 0; i < info.length(); i++ )
815       if ( info.at( i ) == '\n' )
816         msg += QString( "<br>" );
817       else
818         msg += info.at( i );
819
820     info = QString( "<p><nobr>%1</nobr></p>" ).arg( msg );
821
822     QMessageBox::critical( controlWidget() ? controlWidget()->topLevelWidget() : 0,
823                            tr( "DATA_ERR_TITLE" ), info, tr( "OK" ) );
824     if ( controlWidget() )
825       controlWidget()->setFocus();
826   }
827   return aState;
828 }
829
830 /*!
831   Add widgets to the vertical box layout.
832 */
833 void QDS_Datum::addTo( QVBoxLayout* l )
834 {
835   initDatum();
836
837   if ( !l )
838     return;
839
840   if ( wrapper( Label ) )
841     l->addWidget( wrapper( Label ) );
842   if ( wrapper( Control ) )
843     l->addWidget( wrapper( Control ) );
844   if ( wrapper( Units ) )
845     l->addWidget( wrapper( Units ) );
846 }
847
848 /*!
849   Add widgets to the horizaontal box layout.
850 */
851 void QDS_Datum::addTo( QHBoxLayout* l )
852 {
853   initDatum();
854
855   if ( !l )
856     return;
857
858   if ( wrapper( Label ) )
859     l->addWidget( wrapper( Label ) );
860   if ( wrapper( Control ) )
861     l->addWidget( wrapper( Control ) );
862   if ( wrapper( Units ) )
863     l->addWidget( unitsWidget() );
864 }
865
866 /*!
867   Add widgets to the grid layout.
868 */
869 void QDS_Datum::addTo( QGridLayout* theLay, const int theRow, const int theCol, bool vertical )
870 {
871   initDatum();
872
873   if ( !theLay )
874     return;
875
876   int row = theRow;
877   int col = theCol;
878   if ( wrapper( Label ) )
879   {
880     theLay->addWidget( wrapper( Label ), row, col );
881     vertical ? row++ : col++;
882   }
883   if ( wrapper( Control ) )
884   {
885     theLay->addWidget( wrapper( Control ), row, col );
886     vertical ? row++ : col++;
887   }
888   if ( wrapper( Units ) )
889     theLay->addWidget( wrapper( Units ), row, col );
890 }
891
892 /*!
893   Set the aligment of Label or Units. For Control nothing happens.
894 */
895 void QDS_Datum::setAlignment( const int align, const int type )
896 {
897   initDatum();
898
899   if ( ( type & Label ) && labelWidget() )
900     labelWidget()->setAlignment( align );
901   if ( ( type & Units ) && unitsWidget() )
902     unitsWidget()->setAlignment( align );
903 }
904
905 /*!
906   Perform delayed initialisation. Reimplemented for internal reasons.
907 */
908 bool QDS_Datum::eventFilter( QObject* o, QEvent* e )
909 {
910   if ( o == parent() )
911   {
912     if ( e->type() == QEvent::Show || e->type() == QEvent::ShowToParent ||
913          ( e->type() == QEvent::ChildInserted && ((QChildEvent*)e)->child() == this ) )
914       initDatum();
915   }
916   return QObject::eventFilter( o, e );
917 }
918
919 /*!
920   Notify about parameter value changing.
921 */
922 void QDS_Datum::onParamChanged()
923 {
924 }
925
926 /*!
927   Perform delayed initialization.
928 */
929 void QDS_Datum::onInitDatum()
930 {
931   initDatum();
932 }
933
934 /*!
935   Notify about subwidgets destroying. Allow to avoid repeated deleting in destructor.
936 */
937 void QDS_Datum::onDestroyed( QObject* obj )
938 {
939   myWrapper.remove( wrapperType( (Wrapper*)obj ) );
940 }
941
942 /*!
943   Returns QLabel widget which contains dictionary item label.
944 */
945 QLabel* QDS_Datum::labelWidget() const
946 {
947   initDatum();
948   return myLabel;
949 }
950
951 /*!
952   Returns QLabel widget which contains dictionary item units.
953 */
954 QLabel* QDS_Datum::unitsWidget() const
955 {
956   initDatum();
957   return myUnits;
958 }
959
960 /*!
961   Returns QWidget which contains user input data.
962 */
963 QWidget* QDS_Datum::controlWidget() const
964 {
965   initDatum();
966   return myControl;
967 }
968
969 /*!
970   Returns the dictionary item from the datum.
971 */
972 Handle(DDS_DicItem) QDS_Datum::dicItem() const
973 {
974   return myDicItem;
975 }
976
977 /*!
978   Set the dictionary item in to the datum.
979 */
980 void QDS_Datum::setDicItem( const Handle(DDS_DicItem)& item )
981 {
982   myDicItem = item;
983 }
984
985 /*!
986   Creates QLabel widget for dictionary item label.
987 */
988 QLabel* QDS_Datum::createLabel( QWidget* parent )
989 {
990   return new QLabel( parent );
991 }
992
993 /*!
994   Creates QLabel widget for dictionary item units.
995 */
996 QLabel* QDS_Datum::createUnits( QWidget* parent )
997 {
998   return new QLabel( parent );
999 }
1000
1001 /*!
1002   Creates and returns validator accordance to datum type of value.
1003 */
1004 QValidator* QDS_Datum::validator( const bool limits ) const
1005 {
1006   QValidator* aValidator = 0;
1007
1008   QString fltr = filter();
1009
1010   if ( type() == DDS_DicItem::String )
1011   {
1012     QString aFlags;
1013     QString aFormat = canonicalFormat( format(), aFlags );
1014
1015     int len = -1;
1016     int pos = aFormat.find( "." );
1017     if ( pos != -1 )
1018     {
1019       QString numStr = aFormat.mid( pos + 1, aFormat.length() - pos - 2 );
1020       bool ok;
1021       int numVal = numStr.toInt( &ok );
1022       if ( ok )
1023         len = numVal;
1024     }
1025
1026     QDS_StringValidator* aStrVal = new QDS_StringValidator( fltr, aFlags, (QObject*)this );
1027     aStrVal->setLength( len );
1028
1029     aValidator = aStrVal;
1030   }
1031   else if ( type() == DDS_DicItem::Integer )
1032   {
1033     QDS_IntegerValidator* aIntVal = new QDS_IntegerValidator( fltr, (QObject*)this );
1034
1035     bool ok;
1036     int limit;
1037     limit = minValue().toInt( &ok );
1038     if ( ok && limits )
1039       aIntVal->setBottom( limit );
1040     limit = maxValue().toInt( &ok );
1041     if ( ok && limits )
1042       aIntVal->setTop( limit );
1043
1044     aValidator = aIntVal;
1045   }
1046   else if ( type() == DDS_DicItem::Float )
1047   {
1048     QDS_DoubleValidator* aFloatVal = new QDS_DoubleValidator( fltr, (QObject*)this );
1049
1050     bool ok;
1051     double limit;
1052     limit = minValue().toDouble( &ok );
1053     if ( ok && limits )
1054       aFloatVal->setBottom( limit );
1055     limit = maxValue().toDouble( &ok );
1056     if ( ok && limits )
1057       aFloatVal->setTop( limit );
1058
1059     aValidator = aFloatVal;
1060   }
1061
1062   return aValidator;
1063 }
1064
1065 /*!
1066   Checks the given string are valid or not.
1067 */
1068 bool QDS_Datum::validate( const QString& txt ) const
1069 {
1070   if ( type() == DDS_DicItem::Unknown ||
1071        type() == DDS_DicItem::String && isDoubleFormat( format() ) )
1072     return true;
1073
1074   QValidator* aValidator = validator( true );
1075
1076   if ( !aValidator )
1077     return true;
1078
1079   int pos = 0;
1080   QString str( txt );
1081   bool res = aValidator->validate( str, pos ) == QValidator::Acceptable;
1082
1083   delete aValidator;
1084
1085   return res;
1086 }
1087
1088 /*!
1089   Retrieves information from dictionary and create subwidgets using virtual mechanism.
1090   Virtual mechanism doesn't work in constructor and destructor, therefore this method should
1091   be called outside the constructor.
1092 */
1093 void QDS_Datum::initialize()
1094 {
1095   if ( wrapper( Label ) )
1096     wrapper( Label )->setWidget( myLabel = createLabel( wrapper( Label ) ) );
1097   if ( wrapper( Control ) )
1098     wrapper( Control )->setWidget( myControl = createControl( wrapper( Control ) ) );
1099   if ( wrapper( Units ) )
1100     wrapper( Units )->setWidget( myUnits = createUnits( wrapper( Units ) ) );
1101
1102   TCollection_AsciiString comp;
1103   Handle(DDS_DicItem) item = dicItem();
1104   if ( !item.IsNull() )
1105     comp = item->GetComponent();
1106
1107   QString unitSystem;
1108   Handle(DDS_Dictionary) dic = DDS_Dictionary::Get();
1109   if ( !dic.IsNull() )
1110     unitSystem = toQString( comp.IsEmpty() ? dic->GetActiveUnitSystem() :
1111                                              dic->GetActiveUnitSystem( comp ) );
1112
1113   unitSystemChanged( unitSystem );
1114
1115   QWidget* ctrl = controlWidget();
1116   if ( ctrl )
1117   {
1118     QString lDescr = longDescription();
1119     QString sDescr = shortDescription();
1120     if ( !sDescr.isEmpty() )
1121       QToolTip::add( ctrl, sDescr );
1122     if ( !lDescr.isEmpty() )
1123       QWhatsThis::add( ctrl, lDescr );
1124   }
1125
1126   if ( labelWidget() && ctrl && !( flags() & NotAccel ) )
1127     labelWidget()->setBuddy( ctrl );
1128 }
1129
1130 /*!
1131   Notification about active unit system changing. Update label and units texts.
1132 */
1133 void QDS_Datum::unitSystemChanged( const QString& unitSystem )
1134 {
1135   QString labText = label();
1136   QString unitText = unitsToText( units() );
1137
1138   if ( flags() & UnitsWithLabel )
1139   {
1140     if ( labText.isEmpty() )
1141       labText = unitText;
1142     else if ( !unitText.isEmpty() )
1143       labText = QString( "%1 (%2)" ).arg( labText ).arg( unitText );
1144     unitText = QString::null;
1145   }
1146
1147   if ( labelWidget() )
1148     labelWidget()->setText( labText );
1149
1150   if ( unitsWidget() )
1151     unitsWidget()->setText( unitText );
1152
1153   reset();
1154 }
1155
1156 /*!
1157   Covert units into text presentation.
1158 */
1159 QString QDS_Datum::unitsToText( const QString& uni )
1160 {
1161   int pos = -1;
1162   QString aUnits = uni;
1163   while ( ( pos = aUnits.find( "**" ) ) != -1 )
1164   {
1165     aUnits = aUnits.mid( 0, pos ) + QString( "<tt><font size=+2><sup>" ) +
1166              aUnits.mid( pos + 2, 1 ) + QString( "</sup></font></tt>" ) +
1167              aUnits.mid( pos + 3 );
1168   }
1169   return aUnits;
1170 }
1171
1172 /*!
1173   Covert text presentation into internal units format.
1174 */
1175 QString QDS_Datum::textToUnits( const QString& txt )
1176 {
1177   int pos = -1;
1178   QString aUnits = txt;
1179   while ( ( pos = aUnits.find( "<sup>" ) ) != -1 )
1180   {
1181     aUnits.remove( pos, 5 );
1182     aUnits.insert( pos, "**" );
1183   }
1184   while ( ( pos = aUnits.find( "</sup>" ) ) != -1 )
1185     aUnits.remove( pos, 6 );
1186   return aUnits;
1187 }
1188
1189 /*!
1190   Format the specified integer as dictionary item value.
1191 */
1192 QString QDS_Datum::format( const int num, const QString& id, const bool convert )
1193 {
1194   Handle(DDS_DicItem) anItem;
1195   int aNum = num;
1196   QString anUnit;
1197   
1198   QString aFormat;
1199   int aType = DDS_DicItem::Unknown;
1200   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
1201   if ( !aDict.IsNull() )
1202   {
1203     anItem = aDict->GetDicItem( toAsciiString( id ) );
1204     if ( !anItem.IsNull() )
1205     {
1206       aType = anItem->GetType();
1207       aFormat = toQString( anItem->GetFormat( false ) );
1208       if ( convert )
1209         aNum = ( int )anItem->FromSI( aNum );
1210     }
1211   }
1212
1213   return format( aFormat, aType, aNum );
1214 }
1215
1216 /*!
1217   Format the specified double as dictionary item value.
1218 */
1219 QString QDS_Datum::format( const double num, const QString& id, const bool convert )
1220 {
1221   Handle(DDS_DicItem) anItem;
1222   double aNum = num;
1223   QString anUnit;
1224   
1225   QString aFormat;
1226   int aType = DDS_DicItem::Unknown;
1227   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
1228   if ( !aDict.IsNull() )
1229   {
1230     anItem = aDict->GetDicItem( toAsciiString( id ) );
1231     if ( !anItem.IsNull() )
1232     {
1233       aType = anItem->GetType();
1234       aFormat = toQString( anItem->GetFormat( false ) );
1235       if ( convert )
1236         aNum = anItem->FromSI( aNum );
1237     }
1238   }
1239
1240   return format( aFormat, aType, aNum );
1241 }
1242
1243 /*!
1244   Format the specified string as dictionary item value.
1245 */
1246 QString QDS_Datum::format( const QString& str, const QString& id, const bool convert )
1247 {
1248   Handle(DDS_DicItem) anItem;
1249   QString aStr = str;
1250   QString anUnit;
1251
1252   QString aFormat;
1253   int aType = DDS_DicItem::Unknown;
1254   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
1255   if ( !aDict.IsNull() )
1256   {
1257     anItem = aDict->GetDicItem( toAsciiString( id ) );
1258     if ( !anItem.IsNull() )
1259     {
1260       aType = anItem->GetType();
1261       aFormat = toQString( anItem->GetFormat( false ) );
1262       if ( convert )
1263         aStr = QString::number( anItem->FromSI( aStr.toDouble() ), 'f', 16 );
1264     }
1265   }
1266
1267   return format( aFormat, aType, aStr );
1268 }
1269
1270 /*!
1271   Format the given string accordance to dictionary item format.
1272 */
1273 QString QDS_Datum::format( const QString& aFormat, const int aType, const int aValue )
1274 {
1275   QString txt;
1276
1277   if ( !aFormat.isEmpty() )
1278   {
1279     switch ( aType )
1280     {
1281     case DDS_DicItem::Float:
1282       txt = sprintf( aFormat, (double)aValue );
1283       txt = txt.stripWhiteSpace();
1284       break;
1285     case DDS_DicItem::Integer:
1286       txt = sprintf( aFormat, aValue );
1287       txt = txt.stripWhiteSpace();
1288       break;
1289     case DDS_DicItem::String:
1290     default:
1291       txt = sprintf( aFormat, aValue );
1292       break;
1293     }
1294   }
1295   else
1296     txt = QString().setNum( aValue );
1297
1298   return txt;
1299 }
1300
1301 /*!
1302   Format the given string accordance to dictionary item format.
1303 */
1304 QString QDS_Datum::format( const QString& aFormat, const int aType, const double aValue )
1305 {
1306   QString txt;
1307
1308   if ( !aFormat.isEmpty() )
1309   {
1310     switch ( aType )
1311     {
1312     case DDS_DicItem::Float:
1313       txt = QString().sprintf( aFormat, aValue );
1314       txt = txt.stripWhiteSpace();
1315       break;
1316     case DDS_DicItem::Integer:
1317       txt = QString().sprintf( aFormat, (int)aValue );
1318       txt = txt.stripWhiteSpace();
1319       break;
1320     case DDS_DicItem::String:
1321     default:
1322       txt = QString().sprintf( aFormat, aValue );
1323       break;
1324     }
1325   }
1326   else
1327     txt = QString().setNum( aValue, 'g', 16 );
1328
1329   return txt;
1330 }
1331
1332 /*!
1333   Format the given string accordance to dictionary item format.
1334 */
1335 QString QDS_Datum::format( const QString& aFormat, const int aType, const QString& aValue )
1336 {
1337   QString txt = aValue;
1338
1339   if ( aType != DDS_DicItem::String )
1340     txt = txt.stripWhiteSpace();
1341
1342   if ( aFormat.isEmpty() || txt.isEmpty() )
1343     return txt;
1344
1345   switch ( aType )
1346   {
1347   case DDS_DicItem::Float:
1348     txt = txt.replace( 'd', 'e' ).replace( 'D', 'E' );
1349     txt = sprintf( aFormat, txt.toDouble() );
1350     txt = txt.stripWhiteSpace();
1351     break;
1352   case DDS_DicItem::Integer:
1353     txt = sprintf( aFormat, txt.toInt() );
1354     txt = txt.stripWhiteSpace();
1355     break;
1356   case DDS_DicItem::String:
1357     txt = sprintf( aFormat, txt );
1358     break;
1359   }
1360
1361   return txt;
1362 }
1363
1364 /*!
1365   Wrapper around the standard sprintf function.
1366   Process some non standard flags from format string.
1367 */
1368 QString QDS_Datum::sprintf( const QString& fmt, const int val )
1369 {
1370   return QString().sprintf( canonicalFormat( fmt ), val );
1371 }
1372
1373 /*!
1374   Wrapper around the standard sprintf function.
1375   Process some non standard flags from format string.
1376 */
1377 QString QDS_Datum::sprintf( const QString& fmt, const double val )
1378 {
1379   return QString().sprintf( canonicalFormat( fmt ), val );
1380 }
1381
1382 /*!
1383   Wrapper around the standard sprintf function.
1384   Process some non standard flags from format string.
1385 */
1386 QString QDS_Datum::sprintf( const QString& fmt, const QString& val )
1387 {
1388   QString aFlags;
1389   QString aFormat = canonicalFormat( fmt, aFlags );
1390
1391   QString txt = val;
1392
1393   QRegExp rx( "^(%[0-9]*.?[0-9]*s)$" );
1394   if ( aFormat.find( rx ) != -1 )
1395   {
1396     // QString().sprintf() always expects string in UTF8 encoding, so we cannot use it here
1397     char* buf = new char[txt.length() + 1];
1398     ::sprintf( buf, aFormat.latin1(), (const char*)(txt.local8Bit()) );
1399     txt = QString::fromLocal8Bit( buf );
1400
1401     delete[] buf;
1402   }
1403
1404   if ( isDoubleFormat( aFormat ) )
1405   {
1406     /*bool isOk;
1407     double aVal = txt.toDouble( &isOk );
1408     if ( isOk )
1409     {
1410       txt = sprintf( aFormat, aVal );
1411       txt = txt.replace( 'e', 'D' );
1412     }*/
1413   }
1414
1415   if ( aFlags.contains( "u", false ) )
1416     txt = txt.upper();
1417   if ( aFlags.contains( "l", false ) )
1418     txt = txt.lower();
1419
1420   return txt;
1421 }
1422
1423 /*!
1424   Returns the canonical sprintf format.
1425 */
1426 QString QDS_Datum::canonicalFormat( const QString& fmt )
1427 {
1428   QString flags;
1429   return canonicalFormat( fmt, flags );
1430 }
1431
1432 /*!
1433   Returns the canonical sprintf format and non standard flags.
1434 */
1435 QString QDS_Datum::canonicalFormat( const QString& fmt, QString& flags )
1436 {
1437   QString newFmt = fmt;
1438   flags = QString::null;
1439
1440   QRegExp rx( "^(%[0-9]*.?[0-9]*)([a-z,A-Z]+)[g|c|d|i|o|u|x|e|f|n|p|s|X|E|G]$" );
1441   if ( rx.search( newFmt ) >= 0 )
1442   {
1443     flags = rx.cap( 2 );
1444     newFmt.remove( rx.pos( 2 ), flags.length() );
1445   }
1446   return newFmt;
1447 }
1448
1449 /*!
1450   Returns displayable units string for given dictionary item id
1451 */
1452 QString QDS_Datum::units( const QString& id )
1453 {
1454   QString anUnit;
1455   Handle(DDS_DicItem) anItem;
1456
1457   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
1458   if ( !aDict.IsNull() )
1459   {
1460     anItem = aDict->GetDicItem( toAsciiString( id ) );
1461     if ( !anItem.IsNull() )
1462       anUnit = unitsToText( toQString( anItem->GetUnits() ) );
1463   }
1464   return anUnit;
1465 }
1466
1467 /*!
1468   Get prefix string from format.
1469 */
1470 QString QDS_Datum::prefix() const
1471 {
1472   return QString::null;
1473 }
1474
1475 /*!
1476   Get suffix string from format.
1477 */
1478 QString QDS_Datum::suffix() const
1479 {
1480   return QString::null;
1481 }
1482
1483 /*!
1484   Get min value.
1485 */
1486 QString QDS_Datum::minValue() const
1487 {
1488   QString pref = prefix();
1489   QString suff = suffix();
1490
1491   QString aMin = minimumValue().stripWhiteSpace();
1492
1493   if ( !pref.isEmpty() && aMin.left( pref.length() ) == pref )
1494     aMin = aMin.mid( pref.length() );
1495
1496   if ( !suff.isEmpty() && aMin.right( suff.length() ) == suff )
1497     aMin = aMin.mid( 0, aMin.length() - suff.length() );
1498
1499   return aMin;
1500 }
1501
1502 /*!
1503   Get max value.
1504 */
1505 QString QDS_Datum::maxValue() const
1506 {
1507   QString pref = prefix();
1508   QString suff = suffix();
1509
1510   QString aMax = maximumValue().stripWhiteSpace();
1511
1512   if ( !pref.isEmpty() && aMax.left( pref.length() ) == pref )
1513     aMax = aMax.mid( pref.length() );
1514
1515   if ( !suff.isEmpty() && aMax.right( suff.length() ) == suff )
1516     aMax = aMax.mid( 0, aMax.length() - suff.length() );
1517
1518   return aMax;
1519 }
1520
1521 /*!
1522   Reset the numeric value cache.
1523 */
1524 void QDS_Datum::invalidateCache()
1525 {
1526   myTargetValue = QString::null;
1527 }
1528
1529 /*!
1530   Remove the acceleartor tags '&' from specified label string \asrc.
1531 */
1532 QString QDS_Datum::removeAccel( const QString& src )
1533 {
1534   QString trg = src;
1535
1536   for ( uint i = 0; i < trg.length(); )
1537   {
1538     if ( trg.mid( i, 2 ) == QString( "&&" ) )
1539       i += 2;
1540     else if ( trg.at( i ) == '&' )
1541       trg.remove( i, 1 );
1542     else
1543       i++;
1544   }
1545   return trg;
1546 }
1547
1548 /*!
1549   Returns true if given format string \atheFormat has specificator for double values.
1550 */
1551 bool QDS_Datum::isDoubleFormat( const QString& theFormat )
1552 {
1553   if ( theFormat.length() > 0 )
1554   {
1555     QChar c = theFormat[ (int)( theFormat.length() - 1 ) ];
1556       return c == 'f' || c == 'g' || c == 'e' || c == 'G' || c == 'E';
1557   }
1558   else
1559     return false;
1560 }
1561
1562 /*!
1563   Returns datum flags.
1564 */
1565 int QDS_Datum::flags() const
1566 {
1567   return myFlags;
1568 }
1569
1570 /*!
1571   Perform intialization if it needed. [internal]
1572 */
1573 void QDS_Datum::initDatum() const
1574 {
1575   if ( myInitialised )
1576     return;
1577
1578   QDS_Datum* that = (QDS_Datum*)this;
1579   that->myInitialised = true;
1580   that->initialize();
1581
1582   if ( parent() )
1583     parent()->removeEventFilter( this );
1584 }
1585
1586 /*!
1587   Return wrapper for specified subwidget. [internal]
1588 */
1589 QDS_Datum::Wrapper* QDS_Datum::wrapper( QWidget* wid ) const
1590 {
1591   if ( !wid )
1592     return 0;
1593
1594   Wrapper* wrap = 0;
1595   for ( QMap<int, Wrapper*>::ConstIterator it = myWrapper.begin(); it != myWrapper.end() && !wrap; ++it )
1596   {
1597     if ( it.data() && it.data()->widget() == wid )
1598       wrap = it.data();
1599   }
1600   return wrap;
1601 }
1602
1603 /*!
1604   Return wrapper for specified subwidget name. [internal]
1605 */
1606 QDS_Datum::Wrapper* QDS_Datum::wrapper( const int id ) const
1607 {
1608   Wrapper* wrap = 0;
1609   if ( myWrapper.contains( id ) )
1610     wrap = myWrapper[id];
1611   return wrap;
1612 }
1613
1614 /*!
1615   Return subwidget name for specified wrapper. [internal]
1616 */
1617 int QDS_Datum::wrapperType( QDS_Datum::Wrapper* wrap ) const
1618 {
1619   int id = -1;
1620   for ( QMap<int, Wrapper*>::ConstIterator it = myWrapper.begin(); it != myWrapper.end() && id == -1; ++it )
1621   {
1622     if ( it.data() == wrap )
1623       id = it.key();
1624   }
1625   return id;
1626 }