]> SALOME platform Git repositories - modules/gui.git/blob - src/QDS/QDS_Datum.cxx
Salome HOME
ff3ed8aca976a01e49b6db35694a88d853cb4ae8
[modules/gui.git] / src / QDS / QDS_Datum.cxx
1 #include "QDS_Datum.h"
2
3 #include "QDS_Validator.h"
4
5 #include <DDS_Dictionary.h>
6
7 #include <qtimer.h>
8 #include <qlabel.h>
9 #include <qwidget.h>
10 #include <qlayout.h>
11 #include <qtooltip.h>
12 #include <qwhatsthis.h>
13 #include <qvalidator.h>
14 #include <qmessagebox.h>
15
16 /*!
17   Class: QDS_Datum::Wrapper
18   Descr: Wrapper widget for sub widgets. [internal]
19 */
20
21 class QDS_Datum::Wrapper : public QWidget
22 {
23 public:
24   Wrapper( QWidget* = 0 );
25   virtual ~Wrapper();
26
27   QWidget*      widget() const;
28   void          setWidget( QWidget* );
29
30   virtual bool  eventFilter( QObject*, QEvent* );
31
32 protected:
33   virtual void  resizeEvent( QResizeEvent* );
34
35 private:
36   QWidget*      myWid;
37 };
38
39
40 QDS_Datum::Wrapper::Wrapper( QWidget* parent )
41 : QWidget( parent ),
42 myWid( 0 )
43 {
44   QHBoxLayout* base = new QHBoxLayout( this );
45   base->setAutoAdd( true );
46 }
47
48 QDS_Datum::Wrapper::~Wrapper()
49 {
50 }
51
52 QWidget* QDS_Datum::Wrapper::widget() const
53 {
54   return myWid;
55 }
56
57 void QDS_Datum::Wrapper::setWidget( QWidget* wid )
58 {
59   if ( myWid == wid )
60     return;
61
62   if ( myWid )
63     myWid->removeEventFilter( this );
64
65   myWid = wid;
66
67   if ( !myWid )
68     return;
69
70   if ( myWid->parent() != this )
71     myWid->reparent( this, QPoint( 0, 0 ) );
72
73   setFocusProxy( myWid );
74
75   myWid->updateGeometry();
76   updateGeometry();
77
78   myWid->installEventFilter( this );
79 }
80
81 bool QDS_Datum::Wrapper::eventFilter( QObject* o, QEvent* e )
82 {
83   if ( e->type() == QEvent::Resize && o == widget() )
84   {
85     QResizeEvent* re = (QResizeEvent*)e;
86     if ( re->size() != size() )
87       resize( re->size() );
88   }
89   return QWidget::eventFilter( o, e );
90 }
91
92 void QDS_Datum::Wrapper::resizeEvent( QResizeEvent* e )
93 {
94   QWidget::resizeEvent( e );
95
96   if ( widget() && widget()->size() != size() )
97     widget()->resize( size() );
98 }
99
100 /*!
101   Class: QDS_Datum
102   Descr: Base class for control used data dictionary. [public]
103 */
104
105 QDS_Datum::QDS_Datum( const QString& id, QWidget* parent, const int flags, const QString& comp )
106 : QObject( parent ),
107 myId( id ),
108 myLabel( 0 ),
109 myUnits( 0 ),
110 myControl( 0 ),
111 myFlags( flags ),
112 myInitialised( false )
113 {
114   if ( myFlags & Label )
115     myWrapper.insert( Label, new Wrapper( parent ) );
116   if ( myFlags & Control )
117     myWrapper.insert( Control, new Wrapper( parent ) );
118   if ( myFlags & Units )
119     myWrapper.insert( Units, new Wrapper( parent ) );
120
121   for ( QMap<int, Wrapper*>::Iterator it = myWrapper.begin(); it != myWrapper.end(); ++it )
122     connect( it.data(), SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
123
124   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
125   if ( aDict.IsNull() )
126     return;
127
128   TCollection_AsciiString anId = toAsciiString( id );
129   TCollection_AsciiString aComp = toAsciiString( comp );
130
131   if ( aComp.IsEmpty() )
132     setDicItem( aDict->GetDicItem( anId ) );
133   else
134     setDicItem( aDict->GetDicItem( anId, aComp ) );
135
136   QTimer::singleShot( 0, this, SLOT( onInitDatum() ) );
137
138   if ( parent )
139     parent->installEventFilter( this );
140
141   insertDatum( this );
142 }
143
144 QDS_Datum::~QDS_Datum()
145 {
146   removeDatum( this );
147
148   delete myLabel;
149   delete myUnits;
150   delete myControl;
151 /*
152   for ( QMap<int, Wrapper*>::Iterator it = myWrapper.begin(); it != myWrapper.end(); ++it )
153     delete it.data();
154 */
155 }
156
157 QString QDS_Datum::id() const
158 {
159   initDatum();
160
161   return myId;
162 }
163
164 int QDS_Datum::type() const
165 {
166   initDatum();
167
168   int res = DDS_DicItem::Unknown;
169   if ( !myDicItem.IsNull() )
170     res = myDicItem->GetType();
171   return res;
172 }
173
174 QString QDS_Datum::label() const
175 {
176   initDatum();
177
178   QString labStr;
179   if ( !myDicItem.IsNull() )
180     labStr = toQString( myDicItem->GetLabel() );
181
182   if ( flags() & NotAccel )
183     labStr = removeAccel( labStr );
184
185   return labStr;
186 }
187
188 QString QDS_Datum::units() const
189 {
190   initDatum();
191
192   QString unitStr;
193   if ( !myDicItem.IsNull() )
194     unitStr = toQString( myDicItem->GetUnits() );
195   return unitStr;
196 }
197
198 QString QDS_Datum::filter() const
199 {
200   initDatum();
201
202   QString fltr;
203   if ( !myDicItem.IsNull() )
204     fltr = toQString( myDicItem->GetFilter() );
205   return fltr;
206 }
207
208 QString QDS_Datum::format() const
209 {
210   initDatum();
211
212   QString fmtStr;
213   if ( !myDicItem.IsNull() )
214     fmtStr = toQString( myDicItem->GetFormat( false ) );
215   return fmtStr;
216 }
217
218 QString QDS_Datum::defaultValue() const
219 {
220   initDatum();
221
222   QString pref = prefix();
223   QString suff = suffix();
224
225   QString def;
226   if ( !myDicItem.IsNull() )
227     def = toQString( myDicItem->GetDefaultValue() );
228
229   QString aDef = def.stripWhiteSpace();
230   if ( !pref.isEmpty() && aDef.left( pref.length() ) == pref )
231     aDef = aDef.mid( pref.length() );
232
233   if ( !suff.isEmpty() && aDef.right( suff.length() ) == suff )
234     aDef = aDef.mid( 0, aDef.length() - suff.length() );
235
236   return aDef;
237 }
238
239 QString QDS_Datum::minimumValue() const
240 {
241   initDatum();
242
243   QString min;
244   if ( !myDicItem.IsNull() )
245     min = format( format(), type(), myDicItem->GetMinValue() );
246   return min;
247 }
248
249 QString QDS_Datum::maximumValue() const
250 {
251   initDatum();
252
253   QString max;
254   if ( !myDicItem.IsNull() )
255     max = format( format(), type(), myDicItem->GetMaxValue() );
256   return max;
257 }
258
259 QString QDS_Datum::longDescription() const
260 {
261   initDatum();
262
263   QString ldStr;
264   if ( !myDicItem.IsNull() )
265     ldStr = toQString( myDicItem->GetLongDescription() );
266   return ldStr;
267 }
268
269 QString QDS_Datum::shortDescription() const
270 {
271   initDatum();
272
273   QString sdStr;
274   if ( !myDicItem.IsNull() )
275     sdStr = toQString( myDicItem->GetLongDescription() );
276   return sdStr;
277 }
278
279 QString QDS_Datum::stringValue() const
280 {
281   initDatum();
282
283   if ( getString() == myTargetValue )
284     return mySourceValue;
285   else
286     return getString();
287 }
288
289 double QDS_Datum::doubleValue() const
290 {
291   initDatum();
292
293   double res = 0;
294   if ( !myTargetValue.isNull() && myTargetValue == getString() )
295     res = mySourceValue.toDouble();
296   else
297   {
298     res = getString().toDouble();
299     if ( !myDicItem.IsNull() )
300       res = myDicItem->ToSI( res );
301   }
302
303   return res;
304 }
305
306 int QDS_Datum::integerValue() const
307 {
308   initDatum();
309
310   int res = 0;
311   if ( !myTargetValue.isNull() && myTargetValue == getString() )
312     res = mySourceValue.toInt();
313   else
314   {
315     double val = getString().toDouble();
316     if ( !myDicItem.IsNull() )
317       res = (int)myDicItem->ToSI( val );
318   }
319
320   return res;
321 }
322
323 QString QDS_Datum::text() const
324 {
325   initDatum();
326
327   QString aLabel = label();
328   QString aData  = stringValue();
329   QString aUnits = units();
330
331   QString res = aLabel;
332   if ( !res.isEmpty() && !aData.isEmpty() )
333     res += QString( ": " );
334
335   res += aData;
336   if ( !aUnits.isEmpty() )
337     res += QString( " " ) + aUnits;
338
339   return res;
340 }
341
342 bool QDS_Datum::isEmpty() const
343 {
344   return stringValue().isEmpty();
345 }
346
347 void QDS_Datum::reset()
348 {
349   initDatum();
350
351   mySourceValue = defaultValue();
352   setString( format( ( myFlags & NotFormat ) ? (QString) "" : format(), type(), mySourceValue ) );
353   invalidateCache();
354
355   onParamChanged();
356   QString str = getString();
357   emit paramChanged();
358   emit paramChanged( str );
359 }
360
361 void QDS_Datum::clear()
362 {
363   initDatum();
364
365   if ( !getString().isEmpty() )
366   {
367     mySourceValue = "";
368     setString( mySourceValue );
369     invalidateCache();
370
371     onParamChanged();
372     QString str = getString();
373     emit paramChanged();
374     emit paramChanged( str );
375   }
376 }
377
378 void QDS_Datum::setStringValue( const QString& txt )
379 {
380   initDatum();
381
382   mySourceValue = txt;
383   QString aStr = format( ( flags() & NotFormat ) ? (QString) "" : format(), type(), txt );
384   setString( aStr );
385   myTargetValue = aStr;
386
387   onParamChanged();
388   QString str = getString();
389   emit paramChanged();
390   emit paramChanged( str );
391 }
392
393 void QDS_Datum::setDoubleValue( const double num )
394 {
395   initDatum();
396
397   mySourceValue = QString().setNum( num, 'g', 16 );
398   double val = num;
399   if ( !myDicItem.IsNull() )
400     val = myDicItem->FromSI( val );
401
402   QString aStr = format( ( flags() & NotFormat ) ? (QString) "" : format(), type(), val );
403   setString( aStr );
404   myTargetValue = aStr;
405
406   onParamChanged();
407   QString str = getString();
408   emit paramChanged();
409   emit paramChanged( str );
410 }
411
412 void QDS_Datum::setIntegerValue( const int num )
413 {
414   initDatum();
415
416   mySourceValue = QString().setNum( num );
417   double val = num;
418   if ( !myDicItem.IsNull() )
419     val = myDicItem->FromSI( val );
420
421   QString aStr = format( ( flags() & NotFormat ) ? (QString) "" : format(), type(), val );
422   setString( aStr );
423   myTargetValue = aStr;
424
425   onParamChanged();
426   QString str = getString();
427   emit paramChanged();
428   emit paramChanged( str );
429 }
430
431 /*!
432   Returns true if all subwidgets specified by 'element' enabled.
433 */
434 bool QDS_Datum::isEnabled( const int element ) const
435 {
436   initDatum();
437
438   bool res = true;
439   if ( element & Label )
440     res = res && labelWidget() && labelWidget()->isEnabled();
441   if ( element & Units )
442     res = res && unitsWidget() && unitsWidget()->isEnabled();
443   if ( element & Control )
444     res = res && controlWidget() && controlWidget()->isEnabled();
445   return res;
446 }
447
448 /*!
449   Enable/Disable subwidgets specified by 'element'.
450   Values: Label, Control, Units or their combinations.
451 */
452 void QDS_Datum::setEnabled( const bool on, const int element )
453 {
454   initDatum();
455
456   if ( element & Label && labelWidget() )
457     labelWidget()->setEnabled( on );
458   if ( element & Units && unitsWidget() )
459     unitsWidget()->setEnabled( on );
460   if ( element & Control && controlWidget() )
461     controlWidget()->setEnabled( on );
462 }
463
464 /*!
465   Enable/Disable control.
466 */
467 void QDS_Datum::setEnabled( bool on )
468 {
469   setEnabled( on, Control );
470 }
471
472 void QDS_Datum::setShown( const bool visible, const int flags )
473 {
474   if ( visible )
475     show( flags );
476   else
477     hide( flags );
478 }
479
480 /*!
481   Show subwidgets specified by 'element'.
482   Values: Label, Control, Units or their combinations.
483 */
484 void QDS_Datum::show( const int element )
485 {
486   initDatum();
487
488   if ( ( element & Label ) && labelWidget() )
489     labelWidget()->show();
490   if ( ( element & Units ) && unitsWidget() )
491     unitsWidget()->show();
492   if ( ( element & Control ) && controlWidget() )
493     controlWidget()->show();
494 }
495
496 /*!
497   Hide subwidgets specified by 'element'.
498   Values: Label, Control, Units or their combinations.
499 */
500 void QDS_Datum::hide( const int element )
501 {
502   initDatum();
503
504   if ( ( element & Label ) && labelWidget() )
505     labelWidget()->hide();
506   if ( ( element & Units ) && unitsWidget() )
507     unitsWidget()->hide();
508   if ( ( element & Control ) && controlWidget() )
509     controlWidget()->hide();
510 }
511
512 /*!
513   Returns subwidget specified by 'element'.
514   Possible values: Label, Control, Units.
515 */
516 QWidget* QDS_Datum::widget( const int element ) const
517 {
518   initDatum();
519   return wrapper( element );
520 }
521
522 /*!
523   Set the input focus on the control widget.
524 */
525 void QDS_Datum::setFocus()
526 {
527   initDatum();
528
529   if ( controlWidget() )
530     controlWidget()->setFocus();
531 }
532
533 /*!
534   Returns true if control contains valid value otherwise returns false
535   and display warning message box if parameter msgBox is set.
536 */
537 bool QDS_Datum::isValid( const bool msgBox, const QString& extMsg, const QString& extLabel ) const
538 {
539   initDatum();
540
541   if ( type() == DDS_DicItem::String && isDoubleFormat( format() ) )
542     return true;
543
544   bool aState = true;
545   QString aStr = getString();
546   if ( aStr.isEmpty() )
547     aState = false;
548   else
549     aState = validate( aStr );
550
551   if ( msgBox && !aState )
552   {
553     QString info;
554     if ( !label().isEmpty() )
555       info += tr( "DATA_INCORRECT_VALUE" ).arg( label() );
556     else if ( !extLabel.isEmpty() )
557       info += tr( "DATA_INCORRECT_VALUE" ).arg( extLabel );
558
559     QString typeStr;
560     switch ( type() )
561     {
562     case DDS_DicItem::String:
563       typeStr = tr( "DATA_STRING" );
564       break;
565     case DDS_DicItem::Integer:
566       typeStr = tr( "DATA_INTEGER" );
567       break;
568     case DDS_DicItem::Float:
569       typeStr = tr( "DATA_FLOAT" );
570       break;
571     default:
572       typeStr = tr( "DATA_NON_EMPTY" );
573       break;
574     }
575     info += ( info.isEmpty() ? (QString) "" : QString( "\n" ) ) + 
576             tr( "DATA_SHOULD_BE_VALUE" ).arg( typeStr );
577     QString limit;
578     if ( type() == DDS_DicItem::Float || type() == DDS_DicItem::Integer )
579     {
580       QString aMinValue = minValue();
581       QString aMaxValue = maxValue();
582       if ( !aMinValue.isEmpty() && !aMaxValue.isEmpty() )
583         limit = tr( "DATA_RANGE" ).arg( aMinValue ).arg( aMaxValue );
584       else if ( !aMinValue.isEmpty() )
585         limit = tr( "DATA_MIN_LIMIT" ).arg( aMinValue );
586       else if ( !aMaxValue.isEmpty() )
587         limit = tr( "DATA_MAX_LIMIT" ).arg( aMaxValue );
588     }
589     if ( !limit.isEmpty() )
590       info += limit;
591
592     info += QString( ".\n" ) + tr( "DATA_INPUT_VALUE" );
593
594     if ( !extMsg.isEmpty() )
595       info += QString( "\n" ) + extMsg;
596
597     QString msg;
598     for ( uint i = 0; i < info.length(); i++ )
599       if ( info.at( i ) == '\n' )
600         msg += QString( "<br>" );
601       else
602         msg += info.at( i );
603
604     info = QString( "<p><nobr>%1</nobr></p>" ).arg( msg );
605
606     QMessageBox::critical( controlWidget() ? controlWidget()->topLevelWidget() : 0,
607                            tr( "DATA_ERR_TITLE" ), info, tr( "BUT_OK" ) );
608     if ( controlWidget() )
609       controlWidget()->setFocus();
610   }
611   return aState;
612 }
613
614 /*!
615   Add widgets to the vertical layout.
616 */
617 void QDS_Datum::addTo( QVBoxLayout* l )
618 {
619   initDatum();
620
621   if ( !l )
622     return;
623
624   if ( wrapper( Label ) )
625     l->addWidget( wrapper( Label ) );
626   if ( wrapper( Control ) )
627     l->addWidget( wrapper( Control ) );
628   if ( wrapper( Units ) )
629     l->addWidget( wrapper( Units ) );
630 }
631
632 /*!
633   Add widgets to the horizaontal layout.
634 */
635 void QDS_Datum::addTo( QHBoxLayout* l )
636 {
637   initDatum();
638
639   if ( !l )
640     return;
641
642   if ( wrapper( Label ) )
643     l->addWidget( wrapper( Label ) );
644   if ( wrapper( Control ) )
645     l->addWidget( wrapper( Control ) );
646   if ( wrapper( Units ) )
647     l->addWidget( unitsWidget() );
648 }
649
650 /*!
651   Add widgets to the grid layout.
652 */
653 void QDS_Datum::addTo( QGridLayout* theLay, const int theRow, const int theCol, bool vertical )
654 {
655   initDatum();
656
657   if ( !theLay )
658     return;
659
660   int row = theRow;
661   int col = theCol;
662   if ( wrapper( Label ) )
663   {
664     theLay->addWidget( wrapper( Label ), row, col );
665     vertical ? row++ : col++;
666   }
667   if ( wrapper( Control ) )
668   {
669     theLay->addWidget( wrapper( Control ), row, col );
670     vertical ? row++ : col++;
671   }
672   if ( wrapper( Units ) )
673     theLay->addWidget( wrapper( Units ), row, col );
674 }
675
676 /*!
677   Set the aligment of Label or Units. For Control nothing happens.
678 */
679 void QDS_Datum::setAlignment( const int align, const int type )
680 {
681   initDatum();
682
683   if ( ( type & Label ) && labelWidget() )
684     labelWidget()->setAlignment( align );
685   if ( ( type & Units ) && unitsWidget() )
686     unitsWidget()->setAlignment( align );
687 }
688
689 bool QDS_Datum::eventFilter( QObject* o, QEvent* e )
690 {
691   if ( o == parent() )
692   {
693     if ( e->type() == QEvent::Show || e->type() == QEvent::ShowToParent ||
694          ( e->type() == QEvent::ChildInserted && ((QChildEvent*)e)->child() == this ) )
695       initDatum();
696   }
697   return QObject::eventFilter( o, e );
698 }
699
700 /*!
701   Notify about parameter changing.
702 */
703 void QDS_Datum::onParamChanged()
704 {
705 }
706
707 /*!
708   Delayed initialization.
709 */
710 void QDS_Datum::onInitDatum()
711 {
712   initDatum();
713 }
714
715 /*!
716   Notify about subwidgets destroying. Allow to avoid repeated deleting in destructor.
717 */
718 void QDS_Datum::onDestroyed( QObject* obj )
719 {
720   myWrapper.remove( wrapperType( (Wrapper*)obj ) );
721 }
722
723 /*!
724   Returns QLabel instance which contains data dictionary label.
725 */
726 QLabel* QDS_Datum::labelWidget() const
727 {
728   initDatum();
729   return myLabel;
730 }
731
732 /*!
733   Returns QLabel instance which contains data dictionary units.
734 */
735 QLabel* QDS_Datum::unitsWidget() const
736 {
737   initDatum();
738   return myUnits;
739 }
740
741 /*!
742   Returns QWidget which contains user input data.
743 */
744 QWidget* QDS_Datum::controlWidget() const
745 {
746   initDatum();
747   return myControl;
748 }
749
750 /*!
751   Returns the dictionary item from the datum.
752 */
753 Handle(DDS_DicItem) QDS_Datum::dicItem() const
754 {
755   return myDicItem;
756 }
757
758 /*!
759   Set the dictionary item in to the datum.
760 */
761 void QDS_Datum::setDicItem( const Handle(DDS_DicItem)& item )
762 {
763   myDicItem = item;
764 }
765
766 /*!
767   Creates QLabel widget for data label.
768 */
769 QLabel* QDS_Datum::createLabel( QWidget* parent )
770 {
771   return new QLabel( parent );
772 }
773
774 /*!
775   Creates QLabel widget for data units.
776 */
777 QLabel* QDS_Datum::createUnits( QWidget* parent )
778 {
779   return new QLabel( parent );
780 }
781
782 /*!
783   Returns validator accordance to data type.
784 */
785 QValidator* QDS_Datum::validator( const bool limits ) const
786 {
787   QValidator* aValidator = 0;
788
789   QString fltr = filter();
790
791   if ( type() == DDS_DicItem::String )
792   {
793     QString aFlags;
794     QString aFormat = canonicalFormat( format(), aFlags );
795
796     int len = -1;
797     int pos = aFormat.find( "." );
798     if ( pos != -1 )
799     {
800       QString numStr = aFormat.mid( pos + 1, aFormat.length() - pos - 2 );
801       bool ok;
802       int numVal = numStr.toInt( &ok );
803       if ( ok )
804         len = numVal;
805     }
806
807     QDS_StringValidator* aStrVal = new QDS_StringValidator( fltr, aFlags, (QObject*)this );
808     aStrVal->setLength( len );
809
810     aValidator = aStrVal;
811   }
812   else if ( type() == DDS_DicItem::Integer )
813   {
814     QDS_IntegerValidator* aIntVal = new QDS_IntegerValidator( fltr, (QObject*)this );
815
816     bool ok;
817     int limit;
818     limit = minValue().toInt( &ok );
819     if ( ok && limits )
820       aIntVal->setBottom( limit );
821     limit = maxValue().toInt( &ok );
822     if ( ok && limits )
823       aIntVal->setTop( limit );
824
825     aValidator = aIntVal;
826   }
827   else if ( type() == DDS_DicItem::Float )
828   {
829     QDS_DoubleValidator* aFloatVal = new QDS_DoubleValidator( fltr, (QObject*)this );
830
831     bool ok;
832     double limit;
833     limit = minValue().toDouble( &ok );
834     if ( ok && limits )
835       aFloatVal->setBottom( limit );
836     limit = maxValue().toDouble( &ok );
837     if ( ok && limits )
838       aFloatVal->setTop( limit );
839
840     aValidator = aFloatVal;
841   }
842
843   return aValidator;
844 }
845
846 /*!
847   Checks the given string are valid or not.
848 */
849 bool QDS_Datum::validate( const QString& txt ) const
850 {
851   if ( type() == DDS_DicItem::Unknown ||
852        type() == DDS_DicItem::String && isDoubleFormat( format() ) )
853     return true;
854
855   QValidator* aValidator = validator( true );
856
857   if ( !aValidator )
858     return true;
859
860   int pos = 0;
861   QString str( txt );
862   bool res = aValidator->validate( str, pos ) == QValidator::Acceptable;
863
864   delete aValidator;
865
866   return res;
867 }
868
869 /*!
870   Retrieves information from data dictionary and create subwidgets using virtual mechanism.
871   Virtual mechanism doesn't work in constructor and destructor, therefore this method should
872   be called outside the constructor.
873 */
874 void QDS_Datum::initialize()
875 {
876   if ( wrapper( Label ) )
877     wrapper( Label )->setWidget( myLabel = createLabel( wrapper( Label ) ) );
878   if ( wrapper( Control ) )
879     wrapper( Control )->setWidget( myControl = createControl( wrapper( Control ) ) );
880   if ( wrapper( Units ) )
881     wrapper( Units )->setWidget( myUnits = createUnits( wrapper( Units ) ) );
882
883   TCollection_AsciiString comp;
884   Handle(DDS_DicItem) item = dicItem();
885   if ( !item.IsNull() )
886     comp = item->GetComponent();
887
888   QString unitSystem;
889   Handle(DDS_Dictionary) dic = DDS_Dictionary::Get();
890   if ( !dic.IsNull() )
891     unitSystem = toQString( comp.IsEmpty() ? dic->GetActiveUnitSystem() :
892                                              dic->GetActiveUnitSystem( comp ) );
893
894   unitSystemChanged( unitSystem );
895
896   QWidget* ctrl = controlWidget();
897   if ( ctrl )
898   {
899     QString lDescr = longDescription();
900     QString sDescr = shortDescription();
901     if ( !sDescr.isEmpty() )
902       QToolTip::add( ctrl, sDescr );
903     if ( !lDescr.isEmpty() )
904       QWhatsThis::add( ctrl, lDescr );
905   }
906
907   if ( labelWidget() && ctrl && !( flags() & NotAccel ) )
908     labelWidget()->setBuddy( ctrl );
909 }
910
911 void QDS_Datum::unitSystemChanged( const QString& unitSystem )
912 {
913   QString labText = label();
914   QString unitText = unitsToText( units() );
915
916   if ( flags() & UnitsWithLabel )
917   {
918     if ( labText.isEmpty() )
919       labText = unitText;
920     else if ( !unitText.isEmpty() )
921       labText = QString( "%1 (%2)" ).arg( labText ).arg( unitText );
922     unitText = QString::null;
923   }
924
925   if ( labelWidget() )
926     labelWidget()->setText( labText );
927
928   if ( unitsWidget() )
929     unitsWidget()->setText( unitText );
930
931   reset();
932 }
933
934 /*!
935   Covert units into text presentation.
936 */
937 QString QDS_Datum::unitsToText( const QString& uni )
938 {
939   int pos = -1;
940   QString aUnits = uni;
941   while ( ( pos = aUnits.find( "**" ) ) != -1 )
942   {
943     aUnits = aUnits.mid( 0, pos ) + QString( "<tt><font size=+2><sup>" ) +
944              aUnits.mid( pos + 2, 1 ) + QString( "</sup></font></tt>" ) +
945              aUnits.mid( pos + 3 );
946   }
947   return aUnits;
948 }
949
950 /*!
951   Covert text presentation into internal units format.
952 */
953 QString QDS_Datum::textToUnits( const QString& txt )
954 {
955   int pos = -1;
956   QString aUnits = txt;
957   while ( ( pos = aUnits.find( "<sup>" ) ) != -1 )
958   {
959     aUnits.remove( pos, 5 );
960     aUnits.insert( pos, "**" );
961   }
962   while ( ( pos = aUnits.find( "</sup>" ) ) != -1 )
963     aUnits.remove( pos, 6 );
964   return aUnits;
965 }
966
967 /*!
968   Format the specified integer as data dictionary value.
969 */
970 QString QDS_Datum::format( const int num, const QString& id, const bool convert )
971 {
972   Handle(DDS_DicItem) anItem;
973   int aNum = num;
974   QString anUnit;
975   
976   QString aFormat;
977   int aType = DDS_DicItem::Unknown;
978   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
979   if ( !aDict.IsNull() )
980   {
981     anItem = aDict->GetDicItem( toAsciiString( id ) );
982     if ( !anItem.IsNull() )
983     {
984       aType = anItem->GetType();
985       aFormat = toQString( anItem->GetFormat( false ) );
986       if ( convert )
987         aNum = ( int )anItem->FromSI( aNum );
988     }
989   }
990
991   return format( aFormat, aType, aNum );
992 }
993
994 /*!
995   Format the specified double as data dictionary value.
996 */
997 QString QDS_Datum::format( const double num, const QString& id, const bool convert )
998 {
999   Handle(DDS_DicItem) anItem;
1000   double aNum = num;
1001   QString anUnit;
1002   
1003   QString aFormat;
1004   int aType = DDS_DicItem::Unknown;
1005   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
1006   if ( !aDict.IsNull() )
1007   {
1008     anItem = aDict->GetDicItem( toAsciiString( id ) );
1009     if ( !anItem.IsNull() )
1010     {
1011       aType = anItem->GetType();
1012       aFormat = toQString( anItem->GetFormat( false ) );
1013       if ( convert )
1014         aNum = anItem->FromSI( aNum );
1015     }
1016   }
1017
1018   return format( aFormat, aType, aNum );
1019 }
1020
1021 /*!
1022   Format the specified string as data dictionary value.
1023 */
1024 QString QDS_Datum::format( const QString& str, const QString& id, const bool convert )
1025 {
1026   Handle(DDS_DicItem) anItem;
1027   QString aStr = str;
1028   QString anUnit;
1029
1030   QString aFormat;
1031   int aType = DDS_DicItem::Unknown;
1032   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
1033   if ( !aDict.IsNull() )
1034   {
1035     anItem = aDict->GetDicItem( toAsciiString( id ) );
1036     if ( !anItem.IsNull() )
1037     {
1038       aType = anItem->GetType();
1039       aFormat = toQString( anItem->GetFormat( false ) );
1040       if ( convert )
1041         aStr = QString::number( anItem->FromSI( aStr.toDouble() ), 'f', 16 );
1042     }
1043   }
1044
1045   return format( aFormat, aType, aStr );
1046 }
1047
1048 /*!
1049   Format the given string accordance to data format.
1050 */
1051 QString QDS_Datum::format( const QString& aFormat, const int aType, const int aValue )
1052 {
1053   QString txt;
1054
1055   if ( !aFormat.isEmpty() )
1056   {
1057     switch ( aType )
1058     {
1059     case DDS_DicItem::Float:
1060       txt = sprintf( aFormat, (double)aValue );
1061       txt = txt.stripWhiteSpace();
1062       break;
1063     case DDS_DicItem::Integer:
1064       txt = sprintf( aFormat, aValue );
1065       txt = txt.stripWhiteSpace();
1066       break;
1067     case DDS_DicItem::String:
1068     default:
1069       txt = sprintf( aFormat, aValue );
1070       break;
1071     }
1072   }
1073   else
1074     txt = QString().setNum( aValue );
1075
1076   return txt;
1077 }
1078
1079 /*!
1080   Format the given string accordance to data format.
1081 */
1082 QString QDS_Datum::format( const QString& aFormat, const int aType, const double aValue )
1083 {
1084   QString txt;
1085
1086   if ( !aFormat.isEmpty() )
1087   {
1088     switch ( aType )
1089     {
1090     case DDS_DicItem::Float:
1091       txt = QString().sprintf( aFormat, aValue );
1092       txt = txt.stripWhiteSpace();
1093       break;
1094     case DDS_DicItem::Integer:
1095       txt = QString().sprintf( aFormat, (int)aValue );
1096       txt = txt.stripWhiteSpace();
1097       break;
1098     case DDS_DicItem::String:
1099     default:
1100       txt = QString().sprintf( aFormat, aValue );
1101       break;
1102     }
1103   }
1104   else
1105     txt = QString().setNum( aValue, 'g', 16 );
1106
1107   return txt;
1108 }
1109
1110 /*!
1111   Format the given string accordance to data format.
1112 */
1113 QString QDS_Datum::format( const QString& aFormat, const int aType, const QString& aValue )
1114 {
1115   QString txt = aValue;
1116
1117   if ( aType != DDS_DicItem::String )
1118     txt = txt.stripWhiteSpace();
1119
1120   if ( aFormat.isEmpty() || txt.isEmpty() )
1121     return txt;
1122
1123   switch ( aType )
1124   {
1125   case DDS_DicItem::Float:
1126     txt = txt.replace( 'd', 'e' ).replace( 'D', 'E' );
1127     txt = sprintf( aFormat, txt.toDouble() );
1128     txt = txt.stripWhiteSpace();
1129     break;
1130   case DDS_DicItem::Integer:
1131     txt = sprintf( aFormat, txt.toInt() );
1132     txt = txt.stripWhiteSpace();
1133     break;
1134   case DDS_DicItem::String:
1135     txt = sprintf( aFormat, txt );
1136     break;
1137   }
1138
1139   return txt;
1140 }
1141
1142 /*!
1143   Wrapper around the standard sprintf function.
1144   Process some non standard flags from format string.
1145 */
1146 QString QDS_Datum::sprintf( const QString& fmt, const int val )
1147 {
1148   return QString().sprintf( canonicalFormat( fmt ), val );
1149 }
1150
1151 /*!
1152   Wrapper around the standard sprintf function.
1153   Process some non standard flags from format string.
1154 */
1155 QString QDS_Datum::sprintf( const QString& fmt, const double val )
1156 {
1157   return QString().sprintf( canonicalFormat( fmt ), val );
1158 }
1159
1160 /*!
1161   Wrapper around the standard sprintf function.
1162   Process some non standard flags from format string.
1163 */
1164 QString QDS_Datum::sprintf( const QString& fmt, const QString& val )
1165 {
1166   QString aFlags;
1167   QString aFormat = canonicalFormat( fmt, aFlags );
1168
1169   QString txt = val;
1170
1171   QRegExp rx( "^(%[0-9]*.?[0-9]*s)$" );
1172   if ( aFormat.find( rx ) != -1 )
1173   {
1174     // QString().sprintf() always expects string in UTF8 encoding, so we cannot use it here
1175     char* buf = new char[txt.length() + 1];
1176     ::sprintf( buf, aFormat.latin1(), (const char*)(txt.local8Bit()) );
1177     txt = QString::fromLocal8Bit( buf );
1178
1179     delete[] buf;
1180   }
1181
1182   if ( isDoubleFormat( aFormat ) )
1183   {
1184     /*bool isOk;
1185     double aVal = txt.toDouble( &isOk );
1186     if ( isOk )
1187     {
1188       txt = sprintf( aFormat, aVal );
1189       txt = txt.replace( 'e', 'D' );
1190     }*/
1191   }
1192
1193   if ( aFlags.contains( "u", false ) )
1194     txt = txt.upper();
1195   if ( aFlags.contains( "l", false ) )
1196     txt = txt.lower();
1197
1198   return txt;
1199 }
1200
1201 /*!
1202   Returns the canonical sprintf format.
1203 */
1204 QString QDS_Datum::canonicalFormat( const QString& fmt )
1205 {
1206   QString flags;
1207   return canonicalFormat( fmt, flags );
1208 }
1209
1210 /*!
1211   Returns the canonical sprintf format and non standard flags.
1212 */
1213 QString QDS_Datum::canonicalFormat( const QString& fmt, QString& flags )
1214 {
1215   QString newFmt = fmt;
1216   flags = QString::null;
1217
1218   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]$" );
1219   if ( rx.search( newFmt ) >= 0 )
1220   {
1221     flags = rx.cap( 2 );
1222     newFmt.remove( rx.pos( 2 ), flags.length() );
1223   }
1224   return newFmt;
1225 }
1226
1227 /*!
1228   Returns displayable units string for given DD ID
1229 */
1230 QString QDS_Datum::units( const QString& id )
1231 {
1232   QString anUnit;
1233   Handle(DDS_DicItem) anItem;
1234
1235   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
1236   if ( !aDict.IsNull() )
1237   {
1238     anItem = aDict->GetDicItem( toAsciiString( id ) );
1239     if ( !anItem.IsNull() )
1240       anUnit = unitsToText( toQString( anItem->GetUnits() ) );
1241   }
1242   return anUnit;
1243 }
1244
1245 /*!
1246   Get prefix string from format.
1247 */
1248 QString QDS_Datum::prefix() const
1249 {
1250   return QString::null;
1251 }
1252
1253 /*!
1254   Get suffix string from format.
1255 */
1256 QString QDS_Datum::suffix() const
1257 {
1258   return QString::null;
1259 }
1260
1261 /*!
1262   Get min value.
1263 */
1264 QString QDS_Datum::minValue() const
1265 {
1266   QString pref = prefix();
1267   QString suff = suffix();
1268
1269   QString aMin = minimumValue().stripWhiteSpace();
1270
1271   if ( !pref.isEmpty() && aMin.left( pref.length() ) == pref )
1272     aMin = aMin.mid( pref.length() );
1273
1274   if ( !suff.isEmpty() && aMin.right( suff.length() ) == suff )
1275     aMin = aMin.mid( 0, aMin.length() - suff.length() );
1276
1277   return aMin;
1278 }
1279
1280 /*!
1281   Get max value.
1282 */
1283 QString QDS_Datum::maxValue() const
1284 {
1285   QString pref = prefix();
1286   QString suff = suffix();
1287
1288   QString aMax = maximumValue().stripWhiteSpace();
1289
1290   if ( !pref.isEmpty() && aMax.left( pref.length() ) == pref )
1291     aMax = aMax.mid( pref.length() );
1292
1293   if ( !suff.isEmpty() && aMax.right( suff.length() ) == suff )
1294     aMax = aMax.mid( 0, aMax.length() - suff.length() );
1295
1296   return aMax;
1297 }
1298
1299 /*!
1300   Reset the numeric value cache.
1301 */
1302 void QDS_Datum::invalidateCache()
1303 {
1304   myTargetValue = QString::null;
1305 }
1306
1307 QString QDS_Datum::removeAccel( const QString& src )
1308 {
1309   QString trg = src;
1310
1311   for ( uint i = 0; i < trg.length(); )
1312   {
1313     if ( trg.mid( i, 2 ) == QString( "&&" ) )
1314       i += 2;
1315     else if ( trg.at( i ) == '&' )
1316       trg.remove( i, 1 );
1317     else
1318       i++;
1319   }
1320   return trg;
1321 }
1322
1323 bool QDS_Datum::isDoubleFormat( const QString& theFormat )
1324 {
1325   if ( theFormat.length() > 0 )
1326   {
1327     QChar c = theFormat[ (int)( theFormat.length() - 1 ) ];
1328       return c == 'f' || c == 'g' || c == 'e' || c == 'G' || c == 'E';
1329   }
1330   else
1331     return false;
1332 }
1333
1334 int QDS_Datum::flags() const
1335 {
1336   return myFlags;
1337 }
1338
1339 void QDS_Datum::initDatum() const
1340 {
1341   if ( myInitialised )
1342     return;
1343
1344   QDS_Datum* that = (QDS_Datum*)this;
1345   that->myInitialised = true;
1346   that->initialize();
1347
1348   if ( parent() )
1349     parent()->removeEventFilter( this );
1350 }
1351
1352 QDS_Datum::Wrapper* QDS_Datum::wrapper( QWidget* wid ) const
1353 {
1354   if ( !wid )
1355     return 0;
1356
1357   Wrapper* wrap = 0;
1358   for ( QMap<int, Wrapper*>::ConstIterator it = myWrapper.begin(); it != myWrapper.end() && !wrap; ++it )
1359   {
1360     if ( it.data() && it.data()->widget() == wid )
1361       wrap = it.data();
1362   }
1363   return wrap;
1364 }
1365
1366 QDS_Datum::Wrapper* QDS_Datum::wrapper( const int id ) const
1367 {
1368   Wrapper* wrap = 0;
1369   if ( myWrapper.contains( id ) )
1370     wrap = myWrapper[id];
1371   return wrap;
1372 }
1373
1374 int QDS_Datum::wrapperType( QDS_Datum::Wrapper* wrap ) const
1375 {
1376   int id = -1;
1377   for ( QMap<int, Wrapper*>::ConstIterator it = myWrapper.begin(); it != myWrapper.end() && id == -1; ++it )
1378   {
1379     if ( it.data() == wrap )
1380       id = it.key();
1381   }
1382   return id;
1383 }