Salome HOME
updated copyright message
[modules/gui.git] / src / QDS / QDS_Datum.cxx
1 // Copyright (C) 2007-2023  CEA, EDF, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "QDS_Datum.h"
24
25 #include <QLayout>
26 #include <QVariant>
27 #include <QTimer>
28 #include <QEvent>
29 #include <QMessageBox>
30 #include <QApplication>
31
32 #include "QDS_Validator.h"
33 #include <DDS_Dictionary.h>
34
35 /*!
36   \class QDS_Datum::Wrapper
37   \internal
38   \brief Wrapper for sub widgets.
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 /*!
58   \brief Constructor.
59   \param parent parent widget
60 */
61 QDS_Datum::Wrapper::Wrapper( QWidget* parent )
62 : QWidget( parent ),
63   myWid( 0 )
64 {
65   setLayout( new QHBoxLayout() );
66   layout()->setSpacing( 0 );
67   layout()->setMargin( 0 );
68   setFocusPolicy( Qt::StrongFocus );
69 }
70
71 /*!
72   \brief Destructor.
73 */
74 QDS_Datum::Wrapper::~Wrapper()
75 {
76 }
77
78 /*!
79   \brief Get widget.
80   \return widget
81 */
82 QWidget* QDS_Datum::Wrapper::widget() const
83 {
84   return myWid;
85 }
86
87 /*!
88   \brief Set widget.
89   \param wid widget
90 */
91 void QDS_Datum::Wrapper::setWidget( QWidget* wid )
92 {
93   if ( myWid == wid || !wid )
94     return;
95
96   wid->setParent( this );
97   QHBoxLayout* hl = qobject_cast<QHBoxLayout*>( layout() );
98   if( myWid )
99     hl->removeWidget( myWid );
100   hl->addWidget( wid );
101   myWid = wid;
102
103   setTabOrder( this, myWid );
104   setFocusProxy( myWid );
105
106   myWid->updateGeometry();
107   updateGeometry();
108 }
109
110 /*!
111   \brief Set size policy of the widget.
112   \param sp new size policy
113 */
114 void QDS_Datum::Wrapper::setSizePolicy( QSizePolicy sp )
115 {
116   QWidget::setSizePolicy( sp );
117
118   if ( widget() )
119     widget()->setSizePolicy( sp );
120 }
121
122 /*!
123   \brief Set widget geometry.
124   \param x horizontal position
125   \param y vertical position
126   \param w widget width
127   \param h widget height
128 */
129 void QDS_Datum::Wrapper::setGeometry( int x, int y, int w, int h )
130 {
131   QWidget::setGeometry( x, y, w, h );
132
133   if ( widget() && widget()->size() != size() )
134     widget()->setGeometry( 0, 0, width(), height() );
135 }
136
137 /*!
138   \class QDS_Datum
139   \brief Base class for all controls using the data dictionary. 
140
141   Datum is successor of QObject (not QWidget). This object can have up to three
142   sub widgets named as QDS::Label, QDS::Control and QDS::Units. 
143   User can prevent creation of any of them by setting corresponding subwidgets IDs
144   in the parameter \a flags of the constructor.
145   QDS::Label widget displays label of datum, QDS::Control widget allows 
146   entering the value and QDS::Units widget displays measure units in the active 
147   units system.
148   
149   These widgets are constructed under the parent widget of the datum. 
150   The sub widgets are layouted in the parent widget in the following order: first widget
151   is QDS::Label, it is followed by QDS::Control, and in the end is QDS::Units.
152   User can add these widgets to layout manually using method addTo().
153   Method widget() can be used to retrieve desired widget and place it into layout.
154
155   When QGroupBox is used as parent widget for datum object, all subwidgets are 
156   arranged automatically by the group box according to the column and orientation
157   properties of the QGroupBox.
158
159   Example:
160   \code
161   QGroupBox* box = new QGroupBox( 3, Qt::Horizontal, "datum box" );
162   QDS_Datum* d1  = new QDS_Datum( "datum_1", box, All );
163   QDS_Datum* d2  = new QDS_Datum( "datum_2", box, All );
164   QDS_Datum* d3  = new QDS_Datum( "datum_3", box, All );
165   \endcode
166
167   In this example we create the QGroupBox with 3 horizontal columns. 
168   All the created datum widgets will be placed automatically in 3 rows.
169   Datums will be placed from top to bottom one by one and aligned in he grid.
170
171   Datum value is stored as string. User can get/set this value:
172   - As string : stringValue()/setStringValue().
173   - As integer : integerValue()/setIntegerValue(). Value is converted to/from SI.
174   - As double : doubleValue()/setDoubleValue(). Value is converted to/from SI.
175   - As variant : value()/setValue().
176
177   User can enable/disable datum subwidgets with setEnabled() method, show/hide them
178   with show()/hide() methods, set input focus to datum with setFocus(), set widgets 
179   alignment with setAlignment(), etc.
180 */
181
182 /*!
183   \brief Constructor. 
184
185   Create datum object with datum identifier \a id and parent widget \a parent.
186
187   Parameter \a flags defines behaviour of datum and set of created
188   subwidgets. Default value of this parameter is QDS::All.
189
190   Parameter \a comp specifies the component name which will be used
191   when searching the dictionary item.
192
193   Datum is self-registered in the global list by QDS::insertDatum().
194
195   \param id datum identifier
196   \param parent parent widget
197   \param flags datum flags
198   \param comp component
199 */
200 QDS_Datum::QDS_Datum( const QString& id, QWidget* parent, const int flags, const QString& comp )
201 : QObject( parent ),
202   myId( id ),
203   myFlags( flags ),
204   myLabel( 0 ),
205   myUnits( 0 ),
206   myControl( 0 ),
207   myInitialised( false ),
208   myTr( false )
209 {
210   if ( myFlags & Label )
211     myWrapper.insert( Label, new Wrapper( parent ) );
212   if ( myFlags & Control )
213     myWrapper.insert( Control, new Wrapper( parent ) );
214   if ( myFlags & Units )
215     myWrapper.insert( Units, new Wrapper( parent ) );
216
217   for ( QMap<int, Wrapper*>::Iterator it = myWrapper.begin(); it != myWrapper.end(); ++it )
218     connect( it.value(), SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
219
220   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
221   if ( aDict.IsNull() )
222     return;
223
224   TCollection_AsciiString anId = toAsciiString( id );
225   TCollection_AsciiString aComp = toAsciiString( comp );
226
227   if ( aComp.IsEmpty() )
228     setDicItem( aDict->GetDicItem( anId ) );
229   else
230     setDicItem( aDict->GetDicItem( anId, aComp ) );
231
232   QTimer::singleShot( 0, this, SLOT( onInitDatum() ) );
233
234   if ( parent )
235     parent->installEventFilter( this );
236
237   insertDatum( this );
238 }
239
240 /*!
241   \brief Destructor. 
242
243   Destroy all subwidget. Datum is unregistered from the global list
244   by QDS::removeDatum().
245 */
246 QDS_Datum::~QDS_Datum()
247 {
248   removeDatum( this );
249
250   delete myLabel;
251   delete myUnits;
252   delete myControl;
253 /*
254   for ( QMap<int, Wrapper*>::Iterator it = myWrapper.begin(); it != myWrapper.end(); ++it )
255     delete it.data();
256 */
257 }
258
259 /*!
260   \brief Overloaded operator used to retrieve main subwidget named QDS::Control.
261   \return QDS::Control subwidget
262 */
263 QDS_Datum::operator QWidget*() const
264 {
265   return widget( Control );
266 }
267
268 /*!
269   \brief Get the datum ID.
270   \return datum ID
271 */
272 QString QDS_Datum::id() const
273 {
274   initDatum();
275
276   return myId;
277 }
278
279 /*!
280   \brief Get the datum value type.
281   \return datum value type
282 */
283 int QDS_Datum::type() const
284 {
285   initDatum();
286
287   int res = DDS_DicItem::Unknown;
288   if ( !myDicItem.IsNull() )
289     res = myDicItem->GetType();
290   return res;
291 }
292
293 /*!
294   \brief Return state of custom translation.
295   \return true if custom translation is enabled
296 */
297 bool QDS_Datum::isCustomTr() const
298 {
299   return myTr;
300 }
301
302 /*!
303   \brief Change state of custom translation.
304
305   Custom translation means that text labels of datums are translated
306   with help of standard Qt mechanism of internationalization. In this
307   case special records should be placed into *.ts files under context "QDS".
308   For example, if label has name "myLabel", the corresponding translation
309   should be written:
310   <context>
311     <name>QDS</name>
312     <message>
313         <source>myLabel</source>
314         <translation>myLabel translation</translation>
315     </message>
316     ...
317
318   If custom translation mechanism is deactivated, then labels will be shown
319   with text got from xml data dictionary file
320
321   By default, the custom translation is deactivated
322
323   \param on - if it is true, custom translation is activated, otherwise, deactivated 
324 */
325 void QDS_Datum::enableCustomTr( const bool on )
326 {
327   myTr = on;
328   labelWidget()->setText( label() );
329 }
330
331 /*!
332   \brief Get the datum label text.
333   \return label text
334 */
335 QString QDS_Datum::label() const
336 {
337   initDatum();
338
339   QString labStr;
340   if ( !myDicItem.IsNull() )
341   {
342     labStr = toQString( myDicItem->GetLabel() );
343     if( labStr.isNull() )
344       labStr = toQString( myDicItem->GetId() );
345   }
346   if( myTr && labStr.length()>0 )
347   {
348     QString dest = QApplication::translate( "QDS", labStr.toLatin1().constData() );
349     if( labStr != dest )
350       labStr = dest;
351   }
352   if ( flags() & NotAccel )
353     labStr = removeAccel( labStr );
354   return labStr;
355 }
356
357 /*!
358   \brief Get the datum units text.
359   \return units text
360 */
361 QString QDS_Datum::units() const
362 {
363   initDatum();
364
365   QString unitStr;
366   if ( !myDicItem.IsNull() )
367     unitStr = toQString( myDicItem->GetUnits() );
368   return unitStr;
369 }
370
371 /*!
372   \brief Get the datum filter string.
373   \return filter string
374 */
375 QString QDS_Datum::filter() const
376 {
377   initDatum();
378
379   QString fltr;
380   if ( !myDicItem.IsNull() )
381     fltr = toQString( myDicItem->GetFilter() );
382   return fltr;
383 }
384
385 /*!
386   \brief Get the datum format string
387   \return format string
388 */
389 QString QDS_Datum::format() const
390 {
391   initDatum();
392
393   QString fmtStr;
394   if ( !myDicItem.IsNull() )
395     fmtStr = toQString( myDicItem->GetFormat( false ) );
396   return fmtStr;
397 }
398
399 /*!
400   \brief Get the datum default value
401   \return default value
402 */
403 QString QDS_Datum::defaultValue() const
404 {
405   initDatum();
406
407   QString pref = prefix();
408   QString suff = suffix();
409
410   QString def;
411   if ( !myDicItem.IsNull() )
412     def = toQString( myDicItem->GetDefaultValue() );
413
414   QString aDef = def.trimmed();
415   if ( !pref.isEmpty() && aDef.left( pref.length() ) == pref )
416     aDef = aDef.mid( pref.length() );
417
418   if ( !suff.isEmpty() && aDef.right( suff.length() ) == suff )
419     aDef = aDef.mid( 0, aDef.length() - suff.length() );
420
421   return aDef;
422 }
423
424 /*!
425   \brief Get the datum minimum value.
426   \return minimum value
427 */
428 QString QDS_Datum::minimumValue() const
429 {
430   initDatum();
431
432   QString min;
433   if ( !myDicItem.IsNull() && myDicItem->HasData( DDS_DicItem::MinValue ) )
434       min = format( format(), type(), myDicItem->GetMinValue() );
435   return min;
436 }
437
438 /*!
439   \brief Get the datum maximum value.
440   \return maximum value
441 */
442 QString QDS_Datum::maximumValue() const
443 {
444   initDatum();
445
446   QString max;
447   if ( !myDicItem.IsNull() && myDicItem->HasData( DDS_DicItem::MaxValue ) )
448     max = format( format(), type(), myDicItem->GetMaxValue() );
449   return max;
450 }
451
452 /*!
453   \brief Get the datum long description.
454   \return datum long description
455 */
456 QString QDS_Datum::longDescription() const
457 {
458   initDatum();
459
460   QString ldStr;
461   if ( !myDicItem.IsNull() )
462     ldStr = toQString( myDicItem->GetLongDescription() );
463   return ldStr;
464 }
465
466 /*!
467   \brief Get the datum short description.
468   \return datum short description
469 */
470 QString QDS_Datum::shortDescription() const
471 {
472   initDatum();
473
474   QString sdStr;
475   if ( !myDicItem.IsNull() )
476     sdStr = toQString( myDicItem->GetLongDescription() );
477   return sdStr;
478 }
479
480 /*!
481   \brief Get the datum options names.
482   \return datum options
483 */
484 QStringList QDS_Datum::options() const
485 {
486   QStringList res;
487   if ( !dicItem().IsNull() )
488   {
489     TColStd_SequenceOfAsciiString lst;
490     dicItem()->GetOptionNames( lst );
491     for ( int i = 1; i <= lst.Length(); i++ )
492       res.append( toQString( lst.Value( i ) ) );
493   }
494   return res;
495 }
496
497 /*!
498   \brief Get datum option specified by \a name as QVariant.
499   \return the option value or invalid QVariant if the option does not exist
500 */
501 QVariant QDS_Datum::option( const QString& name ) const
502 {
503   QVariant res;
504   if ( !dicItem().IsNull() )
505     res = QVariant( toQString( dicItem()->GetOption( toAsciiString( name ) ) ) );
506   return res;
507 }
508
509 /*!
510   \brief Get datum option specified by \a name as string.
511   \return the option value or null QString if the option does not exist
512 */
513 QString QDS_Datum::optionString( const QString& name ) const
514 {
515   QString res;
516   if ( !dicItem().IsNull() )
517     res = toQString( dicItem()->GetOption( toAsciiString( name ) ) );
518   return res;
519 }
520
521 /*!
522   \brief Get datum option specified by \a name as double.
523   \return the option value or 0 if the option does not exist
524 */
525 double QDS_Datum::optionDouble( const QString& name ) const
526 {
527   double res = 0;
528   QVariant opt = option( name );
529   if ( opt.isValid() && opt.canConvert( QVariant::Double ) )
530     res = opt.toDouble();
531   return res;
532 }
533
534 /*!
535   \brief Get datum option specified by \a name as integer.
536   \return the option value or 0 if the option does not exist
537 */
538 int QDS_Datum::optionInteger( const QString& name ) const
539 {
540   int res = 0;
541   QVariant opt = option( name );
542   if ( opt.isValid() && opt.canConvert( QVariant::Int ) )
543     res = opt.toInt();
544   return res;
545 }
546
547 /*!
548   \brief Get the datum value as QVariant.
549   \return datum value
550 */
551 QVariant QDS_Datum::value() const
552 {
553   QVariant val;
554   // trying to return QVariant containing value of correct data type
555   if ( dicItem().IsNull() )
556   {
557     if ( !isEmpty() )
558       val = stringValue();
559   }
560   else
561   {
562     switch( type() )
563     {
564       case DDS_DicItem::Float:
565         val = doubleValue();
566         break;
567       case DDS_DicItem::Integer:
568       case DDS_DicItem::List:
569         val = integerValue();
570         break;
571       case DDS_DicItem::String:
572       case DDS_DicItem::Unknown:
573         val = stringValue();
574         break;
575     }
576   }
577   return val;
578 }
579
580 /*!
581   \brief Get the datum value as string.
582   \return datum value converted to string
583 */
584 QString QDS_Datum::stringValue() const
585 {
586   initDatum();
587
588   if ( getString() == myTargetValue )
589     return mySourceValue;
590   else
591     return getString();
592 }
593
594 /*!
595   \brief Get the datum value as double.
596
597   The value is converted according to the measure units in the active units system
598   to measure units in "SI" units system.
599
600   \return datum value converted to double
601 */
602 double QDS_Datum::doubleValue() const
603 {
604   initDatum();
605
606   double res = 0;
607   if ( !myTargetValue.isNull() && myTargetValue == getString() )
608     res = mySourceValue.toDouble();
609   else
610   {
611     res = getString().toDouble();
612     if ( !myDicItem.IsNull() && !( flags() & NotConvert ) )
613       res = myDicItem->ToSI( res );
614   }
615
616   return res;
617 }
618
619 /*!
620   \brief Get the datum value as integer.
621
622   The value is converted according to the measure units in the active units system
623   to measure units in "SI" units system.
624
625   \return datum value converted to integer
626 */
627 int QDS_Datum::integerValue() const
628 {
629   initDatum();
630
631   int res = 0;
632   if ( !myTargetValue.isNull() && myTargetValue == getString() )
633     res = mySourceValue.toInt();
634   else
635   {
636     double val = getString().toDouble();
637     if ( !myDicItem.IsNull() && !( flags() & NotConvert ) )
638       res = (int)myDicItem->ToSI( val );
639   }
640
641   return res;
642 }
643
644 /*!
645   \brief Get the text data from datum.
646
647   Text consists of label, string value and units.
648
649   \return datum text data
650 */
651 QString QDS_Datum::text() const
652 {
653   initDatum();
654
655   QString aLabel = label();
656   QString aData  = stringValue();
657   QString aUnits = units();
658
659   QString res = aLabel;
660   if ( !res.isEmpty() && !aData.isEmpty() )
661     res += QString( ": " );
662
663   res += aData;
664   if ( !aUnits.isEmpty() )
665     res += QString( " " ) + aUnits;
666
667   return res;
668 }
669
670 /*!
671   \brief Check if the datum is empty.
672   \return \c false if datum control has value entered
673 */
674 bool QDS_Datum::isEmpty() const
675 {
676   return stringValue().isEmpty();
677 }
678
679 /*!
680   \brief Reset datum state and set default value as current.
681 */
682 void QDS_Datum::reset()
683 {
684   initDatum();
685
686   mySourceValue = defaultValue();
687   setString( format( ( myFlags & NotFormat ) ? (QString) "" : format(), type(), mySourceValue ) );
688   invalidateCache();
689
690   onParamChanged();
691   QString str = getString();
692   emit paramChanged();
693   emit paramChanged( str );
694 }
695
696 /*!
697   \brief Clear the control.
698 */
699 void QDS_Datum::clear()
700 {
701   initDatum();
702
703   if ( !getString().isEmpty() )
704   {
705     mySourceValue = "";
706     setString( mySourceValue );
707     invalidateCache();
708
709     onParamChanged();
710     QString str = getString();
711     emit paramChanged();
712     emit paramChanged( str );
713   }
714 }
715
716 /*!
717   \brief Set datum value from QVariant object.
718   \param val new value
719 */
720 void QDS_Datum::setValue( const QVariant& val )
721 {
722   // trying to extract data of correct type from QVariant
723   if ( !dicItem().IsNull() )
724   {
725     bool isOk = false;
726     switch( type() )
727     {
728       case DDS_DicItem::Float:
729       {
730         double aDblVal = val.toDouble( &isOk );
731         if ( isOk )
732         {
733           setDoubleValue( aDblVal );
734           return;
735         }
736         break;
737       }
738       case DDS_DicItem::Integer:
739       case DDS_DicItem::List:
740       {
741         int anIntVal = val.toInt( &isOk );
742         if ( isOk )
743         {
744           setIntegerValue( anIntVal );
745           return;
746         }
747         break;
748       }
749       case DDS_DicItem::String:
750       case DDS_DicItem::Unknown:
751         break;
752     }
753   }
754
755   if ( val.isValid() && val.canConvert( QVariant::String ) )
756     setStringValue( val.toString() );
757   else
758     clear();
759 }
760
761 /*!
762   \brief Set datum value from string data.
763   \param txt new value
764 */
765 void QDS_Datum::setStringValue( const QString& txt )
766 {
767   initDatum();
768
769   mySourceValue = txt;
770   QString aStr = format( ( flags() & NotFormat ) ? (QString) "" : format(), type(), txt );
771   setString( aStr );
772   myTargetValue = aStr;
773
774   onParamChanged();
775   QString str = getString();
776   emit paramChanged();
777   emit paramChanged( str );
778 }
779
780 /*!
781   \brief Set datum value from double data.
782
783   The value is converted from measure units in "SI" units system
784   to the measure units in the active units system.
785   Format the value using datum format internal if it is required.
786   
787   \param num new value
788 */
789 void QDS_Datum::setDoubleValue( const double num )
790 {
791   initDatum();
792
793   mySourceValue = QString().setNum( num, 'g', 16 );
794   double val = num;
795   if ( !myDicItem.IsNull() && !( flags() & NotConvert ) )
796     val = myDicItem->FromSI( val );
797
798   QString aStr = format( ( flags() & NotFormat ) ? (QString) "" : format(), type(), val );
799   setString( aStr );
800   myTargetValue = aStr;
801
802   onParamChanged();
803   QString str = getString();
804   emit paramChanged();
805   emit paramChanged( str );
806 }
807
808 /*!
809   \brief Set datum value from integer data.
810
811   The value is converted from measure units in "SI" units system
812   to the measure units in the active units system.
813   Format the value using datum format if it is required.
814   
815   \param num new value
816 */
817 void QDS_Datum::setIntegerValue( const int num )
818 {
819   initDatum();
820
821   mySourceValue = QString().setNum( num );
822   double val = num;
823   if ( !myDicItem.IsNull() && !( flags() & NotConvert ) )
824     val = myDicItem->FromSI( val );
825
826   QString aStr = format( ( flags() & NotFormat ) ? (QString) "" : format(), type(), val );
827   setString( aStr );
828   myTargetValue = aStr;
829
830   onParamChanged();
831   QString str = getString();
832   emit paramChanged();
833   emit paramChanged( str );
834 }
835
836 /*!
837   \brief Get 'enabled' state of the specified subwidget.
838   \param element ORed subwidget flags (QDS::DatumFlags)
839   \return \c true if all subwidgets specified by \a element are enabled
840   \sa setEnabled()
841 */
842 bool QDS_Datum::isEnabled( const int element ) const
843 {
844   initDatum();
845
846   bool res = true;
847   if ( element & Label )
848     res = res && labelWidget() && labelWidget()->isEnabled();
849   if ( element & Units )
850     res = res && unitsWidget() && unitsWidget()->isEnabled();
851   if ( element & Control )
852     res = res && controlWidget() && controlWidget()->isEnabled();
853   return res;
854 }
855
856 /*!
857   \brief Enable/disable subwidgets specified by \a element.
858
859   Possible values of \a element: QDS::Label, QDS::Control, QDS::Units
860   or their ORed combinations.
861
862   \param on new 'enabled' state
863   \param element ORed subwidget flags (QDS::DatumFlags)
864   \sa isEnabled()
865 */
866 void QDS_Datum::setEnabled( const bool on, const int element )
867 {
868   initDatum();
869
870   if ( element & Label && labelWidget() )
871     labelWidget()->setEnabled( on );
872   if ( element & Units && unitsWidget() )
873     unitsWidget()->setEnabled( on );
874   if ( element & Control && controlWidget() )
875     controlWidget()->setEnabled( on );
876 }
877
878 /*!
879   \brief Enable/disable main control subwidget (QDS::Control).
880   \param on new 'enabled' state
881 */
882 void QDS_Datum::setEnabled( bool on )
883 {
884   setEnabled( on, Control );
885 }
886
887 /*!
888   \brief Show/hide subwidgets specified by \a flags.
889
890   Possible values of \a flags: QDS::Label, QDS::Control, QDS::Units
891   or their ORed combinations.
892
893   \param visible new 'visibility' state
894   \param flags ORed subwidget flags (QDS::DatumFlags)
895   \sa show(), hide()
896 */
897 void QDS_Datum::setShown( const bool visible, const int flags )
898 {
899   initDatum();
900
901   uint flag = Units;
902   while ( flag )
903   {
904     if ( flags & flag && widget( flag ) )
905       widget( flag )->setVisible( visible );
906     flag = flag >> 1;
907   }
908 }
909
910 /*!
911   \brief Show subwidgets specified by \a element.
912
913   Possible values of \a element: QDS::Label, QDS::Control, QDS::Units
914   or their ORed combinations.
915
916   \param element ORed subwidget flags (QDS::DatumFlags)
917   \sa hide(), setShown()
918 */
919 void QDS_Datum::show( const int element )
920 {
921   setShown( true, element );
922 }
923
924 /*!
925   \brief Hide subwidgets specified by \a element.
926
927   Possible values of \a element: QDS::Label, QDS::Control, QDS::Units
928   or their ORed combinations.
929
930   \param element ORed subwidget flags (QDS::DatumFlags)
931   \sa show(), setShown()
932 */
933 void QDS_Datum::hide( const int element )
934 {
935   setShown( false, element );
936 }
937
938 /*!
939   \brief Get subwidget specified by \a element.
940
941   Possible values of \a element: QDS::Label, QDS::Control, QDS::Units.
942   
943   \param element subwidget
944   \return widget
945 */
946 QWidget* QDS_Datum::widget( const int element ) const
947 {
948   initDatum();
949   return wrapper( element );
950 }
951
952 /*!
953   \brief Set the input focus to the control widget.
954 */
955 void QDS_Datum::setFocus()
956 {
957   initDatum();
958
959   if ( controlWidget() )
960     controlWidget()->setFocus();
961 }
962
963 /*!
964   \brief Check if input data is valid.
965
966   If data is invalid and \a msgBox is \c true, the warning message box is shown.
967
968   \param msgBox if \c true, show warning message box if input is invalid
969   \param extMsg warning message
970   \param extLabel optional name of the variable (if QDS::Label control is not used) 
971   \return \c true if input data is valid
972 */
973 bool QDS_Datum::isValid( const bool msgBox, const QString& extMsg, const QString& extLabel ) const
974 {
975   initDatum();
976
977   if ( type() == DDS_DicItem::String && isDoubleFormat( format() ) )
978     return true;
979
980   QString req;
981   if ( !dicItem().IsNull() )
982     req = toQString( dicItem()->GetRequired() );
983
984   bool aState = true;
985   QString aStr = getString();
986
987   if ( aStr.isEmpty() )
988     aState = !( req == QString( "yes" ) || req == QString( "true" ) || req.toInt() );
989   else
990     aState = validate( aStr );
991
992   if ( msgBox && !aState )
993   {
994     QString info;
995     if ( !label().isEmpty() )
996       info += tr( "DATA_INCORRECT_VALUE" ).arg( label() );
997     else if ( !extLabel.isEmpty() )
998       info += tr( "DATA_INCORRECT_VALUE" ).arg( extLabel );
999
1000     QString typeStr;
1001     switch ( type() )
1002     {
1003     case DDS_DicItem::String:
1004       typeStr = tr( "DATA_STRING" );
1005       break;
1006     case DDS_DicItem::Integer:
1007       typeStr = tr( "DATA_INTEGER" );
1008       break;
1009     case DDS_DicItem::Float:
1010       typeStr = tr( "DATA_FLOAT" );
1011       break;
1012     default:
1013       typeStr = tr( "DATA_NON_EMPTY" );
1014       break;
1015     }
1016     info += ( info.isEmpty() ? (QString) "" : QString( "\n" ) ) + 
1017             tr( "DATA_SHOULD_BE_VALUE" ).arg( typeStr );
1018     QString limit;
1019     if ( type() == DDS_DicItem::Float || type() == DDS_DicItem::Integer )
1020     {
1021       QString aMinValue = minValue();
1022       QString aMaxValue = maxValue();
1023       if ( !aMinValue.isEmpty() && !aMaxValue.isEmpty() )
1024         limit = tr( "DATA_RANGE" ).arg( aMinValue ).arg( aMaxValue );
1025       else if ( !aMinValue.isEmpty() )
1026         limit = tr( "DATA_MIN_LIMIT" ).arg( aMinValue );
1027       else if ( !aMaxValue.isEmpty() )
1028         limit = tr( "DATA_MAX_LIMIT" ).arg( aMaxValue );
1029     }
1030     if ( !limit.isEmpty() )
1031       info += limit;
1032
1033     info += QString( ".\n" ) + tr( "DATA_INPUT_VALUE" );
1034
1035     if ( !extMsg.isEmpty() )
1036       info += QString( "\n" ) + extMsg;
1037
1038     QString msg;
1039     for ( int i = 0; i < info.length(); i++ )
1040       if ( info.at( i ) == '\n' )
1041         msg += QString( "<br>" );
1042       else
1043         msg += info.at( i );
1044
1045     info = QString( "<p><nobr>%1</nobr></p>" ).arg( msg );
1046
1047     QMessageBox::critical( controlWidget() ? controlWidget()->topLevelWidget() : 0,
1048                            tr( "DATA_ERR_TITLE" ), info, tr( "OK" ) );
1049     if ( controlWidget() )
1050       controlWidget()->setFocus();
1051   }
1052   return aState;
1053 }
1054
1055 /*!
1056   \brief Add widgets to the vertical box layout.
1057   \param l layout
1058 */
1059 void QDS_Datum::addTo( QVBoxLayout* l )
1060 {
1061   initDatum();
1062
1063   if ( !l )
1064     return;
1065
1066   if ( wrapper( Label ) )
1067     l->addWidget( wrapper( Label ) );
1068   if ( wrapper( Control ) )
1069     l->addWidget( wrapper( Control ) );
1070   if ( wrapper( Units ) )
1071     l->addWidget( wrapper( Units ) );
1072 }
1073
1074 /*!
1075   \brief Add widgets to the horizontal box layout.
1076   \param l layout
1077 */
1078 void QDS_Datum::addTo( QHBoxLayout* l )
1079 {
1080   initDatum();
1081
1082   if ( !l )
1083     return;
1084
1085   if ( wrapper( Label ) )
1086     l->addWidget( wrapper( Label ) );
1087   if ( wrapper( Control ) )
1088     l->addWidget( wrapper( Control ) );
1089   if ( wrapper( Units ) )
1090     l->addWidget( wrapper( Units ) );
1091 }
1092
1093 /*!
1094   \brief Add widgets to the grid layout.
1095   \param theLay layout
1096   \param theRow layout row index
1097   \param theCol layout column index
1098   \param vertical if \c true subwidgets are layouted vertically, otherwise - horizontally
1099 */
1100 void QDS_Datum::addTo( QGridLayout* theLay, const int theRow, const int theCol, bool vertical )
1101 {
1102   initDatum();
1103
1104   if ( !theLay )
1105     return;
1106
1107   int row = theRow;
1108   int col = theCol;
1109   if ( wrapper( Label ) )
1110   {
1111     theLay->addWidget( wrapper( Label ), row, col );
1112     vertical ? row++ : col++;
1113   }
1114   if ( wrapper( Control ) )
1115   {
1116     theLay->addWidget( wrapper( Control ), row, col );
1117     vertical ? row++ : col++;
1118   }
1119   if ( wrapper( Units ) )
1120     theLay->addWidget( wrapper( Units ), row, col );
1121 }
1122
1123 /*!
1124   \brief Set the aligment for QDS::Label and/or QDS::Units subwidgets.
1125   \param align alignment type (Qt::Alignment)
1126   \param type ORed subwidget flags
1127 */
1128 void QDS_Datum::setAlignment( const int align, const int type )
1129 {
1130   initDatum();
1131
1132   if ( ( type & Label ) && labelWidget() )
1133     labelWidget()->setAlignment( Qt::Alignment(align) );
1134   if ( ( type & Units ) && unitsWidget() )
1135     unitsWidget()->setAlignment( Qt::Alignment(align) );
1136 }
1137
1138 /*!
1139   \brief Event filter.
1140
1141   Perform delayed initialisation. Reimplemented for internal reasons.
1142   
1143   \param o event reciever object
1144   \param e event
1145   \return \c true if event should be filtered
1146 */
1147 bool QDS_Datum::eventFilter( QObject* o, QEvent* e )
1148 {
1149   if ( o == parent() )
1150   {
1151     if ( e->type() == QEvent::Show || e->type() == QEvent::ShowToParent ||
1152          ( e->type() == QEvent::ChildAdded && ((QChildEvent*)e)->child() == this ) )
1153       initDatum();
1154   }
1155   return QObject::eventFilter( o, e );
1156 }
1157
1158 /*!
1159   \brief Called when datum value is changed.
1160 */
1161 void QDS_Datum::onParamChanged()
1162 {
1163 }
1164
1165 /*!
1166   \brief Perform delayed initialization.
1167 */
1168 void QDS_Datum::onInitDatum()
1169 {
1170   initDatum();
1171 }
1172
1173 /*!
1174   \brief Called when child subwidget is destroued.
1175
1176   Allows avoiding crash of extra calling of the child subwidget destructor.
1177
1178   \param obj object being destroyed
1179 */
1180 void QDS_Datum::onDestroyed( QObject* obj )
1181 {
1182   myWrapper.remove( wrapperType( (Wrapper*)obj ) );
1183 }
1184
1185 /*!
1186   \brief Get QDS::Label widget.
1187   \return label widget
1188 */
1189 QLabel* QDS_Datum::labelWidget() const
1190 {
1191   initDatum();
1192   return myLabel;
1193 }
1194
1195 /*!
1196   \brief Get QDS::Units widget.
1197   \return units widget
1198 */
1199 QLabel* QDS_Datum::unitsWidget() const
1200 {
1201   initDatum();
1202   return myUnits;
1203 }
1204
1205 /*!
1206   \brief Get QDS::Control widget.
1207   \return control widget
1208 */
1209 QWidget* QDS_Datum::controlWidget() const
1210 {
1211   initDatum();
1212   return myControl;
1213 }
1214
1215 /*!
1216   \brief Get the dictionary item from the datum.
1217   \return handle to data dictionary item
1218 */
1219 Handle(DDS_DicItem) QDS_Datum::dicItem() const
1220 {
1221   return myDicItem;
1222 }
1223
1224 /*!
1225   \brief Set the dictionary item to the datum.
1226   \param item handle to data dictionary item
1227 */
1228 void QDS_Datum::setDicItem( const Handle(DDS_DicItem)& item )
1229 {
1230   myDicItem = item;
1231 }
1232
1233 /*!
1234   \brief Create QDS::Label widget.
1235   \param parent parent widget
1236   \return label widget
1237 */
1238 QLabel* QDS_Datum::createLabel( QWidget* parent )
1239 {
1240   return new QLabel( parent );
1241 }
1242
1243 /*!
1244   \brief Create QDS::Units widget.
1245   \param parent parent widget
1246   \return units widget
1247 */
1248 QLabel* QDS_Datum::createUnits( QWidget* parent )
1249 {
1250   return new QLabel( parent );
1251 }
1252
1253 /*!
1254   \fn QWidget* QDS_Datum::createControl( QWidget* parent );
1255   \brief Create QDS::Control widget.
1256
1257   This method should be implemented in the successor classes.
1258
1259   \param parent parent widget
1260   \return control widget
1261 */
1262
1263 /*!
1264   \fn QString QDS_Datum::getString() const;
1265   \brief Get string value from datum.
1266   
1267   This method should be implemented in the successor classes.
1268   
1269   \return datum string value
1270 */
1271
1272 /*
1273   \fn void QDS_Datum::setString( const QString& txt );
1274   \brief Set string value to datum.
1275   
1276   This method should be implemented in the successor classes.
1277   
1278   \param txt new datum string value
1279 */
1280
1281 /*!
1282   \brief Create validator according to the datum type of value.
1283   \param limits if \c true use minimum and maximum value limits
1284   \return validator
1285 */
1286 QValidator* QDS_Datum::validator( const bool limits ) const
1287 {
1288   QValidator* aValidator = 0;
1289
1290   QString fltr = filter();
1291
1292   if ( type() == DDS_DicItem::String )
1293   {
1294     QString aFlags;
1295     QString aFormat = canonicalFormat( format(), aFlags );
1296
1297     int len = -1;
1298     int pos = aFormat.indexOf( "." );
1299     if ( pos != -1 )
1300     {
1301       QString numStr = aFormat.mid( pos + 1, aFormat.length() - pos - 2 );
1302       bool ok;
1303       int numVal = numStr.toInt( &ok );
1304       if ( ok )
1305         len = numVal;
1306     }
1307
1308     QDS_StringValidator* aStrVal = new QDS_StringValidator( fltr, aFlags, (QObject*)this );
1309     aStrVal->setLength( len );
1310
1311     aValidator = aStrVal;
1312   }
1313   else if ( type() == DDS_DicItem::Integer )
1314   {
1315     QDS_IntegerValidator* aIntVal = new QDS_IntegerValidator( fltr, (QObject*)this );
1316
1317     bool ok;
1318     int limit;
1319     limit = minValue().toInt( &ok );
1320     if ( ok && limits )
1321       aIntVal->setBottom( limit );
1322     limit = maxValue().toInt( &ok );
1323     if ( ok && limits )
1324       aIntVal->setTop( limit );
1325
1326     aValidator = aIntVal;
1327   }
1328   else if ( type() == DDS_DicItem::Float )
1329   {
1330     QDS_DoubleValidator* aFloatVal = new QDS_DoubleValidator( fltr, (QObject*)this );
1331
1332     bool ok;
1333     double limit;
1334     limit = minValue().toDouble( &ok );
1335     if ( ok && limits )
1336       aFloatVal->setBottom( limit );
1337     limit = maxValue().toDouble( &ok );
1338     if ( ok && limits )
1339       aFloatVal->setTop( limit );
1340
1341     aValidator = aFloatVal;
1342   }
1343
1344   return aValidator;
1345 }
1346
1347 /*!
1348   \brief Validate the specified string.
1349   \param txt string to be validated
1350   \return \c true if string contains valid data
1351 */
1352 bool QDS_Datum::validate( const QString& txt ) const
1353 {
1354   if ( type() == DDS_DicItem::Unknown ||
1355        ( type() == DDS_DicItem::String && isDoubleFormat( format() ) ) )
1356     return true;
1357
1358   QValidator* aValidator = validator( true );
1359
1360   if ( !aValidator )
1361     return true;
1362
1363   int pos = 0;
1364   QString str( txt );
1365   bool res = aValidator->validate( str, pos ) == QValidator::Acceptable;
1366
1367   delete aValidator;
1368
1369   return res;
1370 }
1371
1372 /*!
1373   \brief Initialize datum.
1374   
1375   Retrieve information from data dictionary and create subwidgets
1376   using virtual mechanism.
1377
1378   Virtual mechanism doesn't work in the constructor, therefore this method should
1379   be called outside the constructor.
1380 */
1381 void QDS_Datum::initialize()
1382 {
1383   if ( wrapper( Label ) )
1384     wrapper( Label )->setWidget( myLabel = createLabel( wrapper( Label ) ) );
1385   if ( wrapper( Control ) )
1386     wrapper( Control )->setWidget( myControl = createControl( wrapper( Control ) ) );
1387   if ( wrapper( Units ) )
1388     wrapper( Units )->setWidget( myUnits = createUnits( wrapper( Units ) ) );
1389
1390   TCollection_AsciiString comp;
1391   Handle(DDS_DicItem) item = dicItem();
1392   if ( !item.IsNull() )
1393     comp = item->GetComponent();
1394
1395   QString unitSystem;
1396   Handle(DDS_Dictionary) dic = DDS_Dictionary::Get();
1397   if ( !dic.IsNull() )
1398     unitSystem = toQString( comp.IsEmpty() ? dic->GetActiveUnitSystem() :
1399                                              dic->GetActiveUnitSystem( comp ) );
1400
1401   unitSystemChanged( unitSystem );
1402
1403   QWidget* ctrl = controlWidget();
1404   if ( ctrl )
1405   {
1406     QString lDescr = longDescription();
1407     QString sDescr = shortDescription();
1408     if ( !sDescr.isEmpty() )
1409       ctrl->setToolTip( sDescr );
1410     if ( !lDescr.isEmpty() )
1411       ctrl->setWhatsThis( lDescr );
1412   }
1413
1414   if ( labelWidget() && ctrl && !( flags() & NotAccel ) )
1415     labelWidget()->setBuddy( ctrl );
1416 }
1417
1418 /*!
1419   \brief Process notification about active units system changing.
1420   
1421   Update label and units widgets.
1422
1423   \param unitSystem new active units system
1424 */
1425 void QDS_Datum::unitSystemChanged( const QString& /*unitSystem*/ )
1426 {
1427   QString labText = label();
1428   QString unitText = unitsToText( units() );
1429
1430   if ( flags() & UnitsWithLabel )
1431   {
1432     if ( labText.isEmpty() )
1433       labText = unitText;
1434     else if ( !unitText.isEmpty() )
1435       labText = QString( "%1 (%2)" ).arg( labText ).arg( unitText );
1436     unitText = QString();
1437   }
1438
1439   if ( labelWidget() )
1440     labelWidget()->setText( labText );
1441
1442   if ( unitsWidget() )
1443     unitsWidget()->setText( unitText );
1444
1445   reset();
1446 }
1447
1448 /*!
1449   \brief Convert units into text presentation.
1450   \param uni units to be converted
1451   \return text presentation of units (rich-text)
1452 */
1453 QString QDS_Datum::unitsToText( const QString& uni )
1454 {
1455   int pos = -1;
1456   QString aUnits = uni;
1457   while ( ( pos = aUnits.indexOf( "**" ) ) != -1 )
1458   {
1459     aUnits = aUnits.mid( 0, pos ) + QString( "<tt><font size=+2><sup>" ) +
1460              aUnits.mid( pos + 2, 1 ) + QString( "</sup></font></tt>" ) +
1461              aUnits.mid( pos + 3 );
1462   }
1463   return aUnits;
1464 }
1465
1466 /*!
1467   \brief Convert text presentation into internal units format.
1468   \param txt text presentation of units (rich-text)
1469   \return units value
1470 */
1471 QString QDS_Datum::textToUnits( const QString& txt )
1472 {
1473   int pos = -1;
1474   QString aUnits = txt;
1475   while ( ( pos = aUnits.indexOf( "<sup>" ) ) != -1 )
1476   {
1477     aUnits.remove( pos, 5 );
1478     aUnits.insert( pos, "**" );
1479   }
1480   while ( ( pos = aUnits.indexOf( "</sup>" ) ) != -1 )
1481     aUnits.remove( pos, 6 );
1482   return aUnits;
1483 }
1484
1485 /*!
1486   \brief Format the specified integer as dictionary item value.
1487   \param num integer value being formatted
1488   \param id data dictionary ID
1489   \param convert if \c true, perform conversion from "SI" units system
1490   \return formatted value
1491 */
1492 QString QDS_Datum::format( const int num, const QString& id, const bool convert )
1493 {
1494   Handle(DDS_DicItem) anItem;
1495   int aNum = num;
1496   QString anUnit;
1497   
1498   QString aFormat;
1499   int aType = DDS_DicItem::Unknown;
1500   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
1501   if ( !aDict.IsNull() )
1502   {
1503     anItem = aDict->GetDicItem( toAsciiString( id ) );
1504     if ( !anItem.IsNull() )
1505     {
1506       aType = anItem->GetType();
1507       aFormat = toQString( anItem->GetFormat( false ) );
1508       if ( convert )
1509         aNum = ( int )anItem->FromSI( aNum );
1510     }
1511   }
1512
1513   return format( aFormat, aType, aNum );
1514 }
1515
1516 /*!
1517   \brief Format the specified double as dictionary item value.
1518   \param num double value being formatted
1519   \param id data dictionary ID
1520   \param convert if \c true, perform conversion from "SI" units system
1521   \return formatted value
1522 */
1523 QString QDS_Datum::format( const double num, const QString& id, const bool convert )
1524 {
1525   Handle(DDS_DicItem) anItem;
1526   double aNum = num;
1527   QString anUnit;
1528   
1529   QString aFormat;
1530   int aType = DDS_DicItem::Unknown;
1531   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
1532   if ( !aDict.IsNull() )
1533   {
1534     anItem = aDict->GetDicItem( toAsciiString( id ) );
1535     if ( !anItem.IsNull() )
1536     {
1537       aType = anItem->GetType();
1538       aFormat = toQString( anItem->GetFormat( false ) );
1539       if ( convert )
1540         aNum = anItem->FromSI( aNum );
1541     }
1542   }
1543
1544   return format( aFormat, aType, aNum );
1545 }
1546
1547 /*!
1548   \brief Format the specified string as dictionary item value.
1549   \param str string value being formatted
1550   \param id data dictionary ID
1551   \param convert if \c true, perform conversion from "SI" units system
1552   \return formatted value
1553 */
1554 QString QDS_Datum::format( const QString& str, const QString& id, const bool convert )
1555 {
1556   Handle(DDS_DicItem) anItem;
1557   QString aStr = str;
1558   QString anUnit;
1559
1560   QString aFormat;
1561   int aType = DDS_DicItem::Unknown;
1562   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
1563   if ( !aDict.IsNull() )
1564   {
1565     anItem = aDict->GetDicItem( toAsciiString( id ) );
1566     if ( !anItem.IsNull() )
1567     {
1568       aType = anItem->GetType();
1569       aFormat = toQString( anItem->GetFormat( false ) );
1570       if ( convert )
1571         aStr = QString::number( anItem->FromSI( aStr.toDouble() ), 'f', 16 );
1572     }
1573   }
1574
1575   return format( aFormat, aType, aStr );
1576 }
1577
1578 /*!
1579   \brief Format the given value according to the data dictionary item type.
1580   \param aFormat format string
1581   \param aType data dictionary item type
1582   \param aValue integer value being formatted
1583   \return formatted value
1584 */
1585 QString QDS_Datum::format( const QString& aFormat, const int aType, const int aValue )
1586 {
1587   QString txt;
1588
1589   if ( !aFormat.isEmpty() )
1590   {
1591     switch ( aType )
1592     {
1593     case DDS_DicItem::Float:
1594       txt = sprintf( aFormat, (double)aValue );
1595       txt = txt.trimmed();
1596       break;
1597     case DDS_DicItem::Integer:
1598       txt = sprintf( aFormat, aValue );
1599       txt = txt.trimmed();
1600       break;
1601     case DDS_DicItem::String:
1602     default:
1603       txt = sprintf( aFormat, aValue );
1604       break;
1605     }
1606   }
1607   else
1608     txt = QString().setNum( aValue );
1609
1610   return txt;
1611 }
1612
1613 /*!
1614   \brief Format the given value according to the data dictionary item type.
1615   \param aFormat format string
1616   \param aType data dictionary item type
1617   \param aValue double value being formatted
1618   \return formatted value
1619 */
1620 QString QDS_Datum::format( const QString& aFormat, const int aType, const double aValue )
1621 {
1622   QString txt;
1623
1624   if ( !aFormat.isEmpty() )
1625   {
1626     switch ( aType )
1627     {
1628     case DDS_DicItem::Float:
1629       txt = QString().sprintf( aFormat.toLatin1().constData(), aValue );
1630       txt = txt.trimmed();
1631       break;
1632     case DDS_DicItem::Integer:
1633       txt = QString().sprintf( aFormat.toLatin1().constData(), (int)aValue );
1634       txt = txt.trimmed();
1635       break;
1636     case DDS_DicItem::String:
1637     default:
1638       txt = QString().sprintf( aFormat.toLatin1().constData(), aValue );
1639       break;
1640     }
1641   }
1642   else
1643     txt = QString().setNum( aValue, 'g', 16 );
1644
1645   return txt;
1646 }
1647
1648 /*!
1649   \brief Format the given value according to the data dictionary item type.
1650   \param aFormat format string
1651   \param aType data dictionary item type
1652   \param aValue string value being formatted
1653   \return formatted value
1654 */
1655 QString QDS_Datum::format( const QString& aFormat, const int aType, const QString& aValue )
1656 {
1657   QString txt = aValue;
1658
1659   if ( aType != DDS_DicItem::String )
1660     txt = txt.trimmed();
1661
1662   if ( aFormat.isEmpty() || txt.isEmpty() )
1663     return txt;
1664
1665   switch ( aType )
1666   {
1667   case DDS_DicItem::Float:
1668     txt = txt.replace( 'd', 'e' ).replace( 'D', 'E' );
1669     txt = sprintf( aFormat, txt.toDouble() );
1670     txt = txt.trimmed();
1671     break;
1672   case DDS_DicItem::Integer:
1673     txt = sprintf( aFormat, txt.toInt() );
1674     txt = txt.trimmed();
1675     break;
1676   case DDS_DicItem::String:
1677     txt = sprintf( aFormat, txt );
1678     break;
1679   }
1680
1681   return txt;
1682 }
1683
1684 /*!
1685   \brief Wrapper around the standard sprintf() function.
1686
1687   Process some non standard flags from format string.
1688
1689   \param fmt string format
1690   \param val value
1691   \return formatted value
1692 */
1693 QString QDS_Datum::sprintf( const QString& fmt, const int val )
1694 {
1695   return QString().sprintf( canonicalFormat( fmt ).toLatin1().constData(), val );
1696 }
1697
1698 /*!
1699   \brief Wrapper around the standard sprintf() function.
1700   \overload
1701
1702   Process some non standard flags from format string.
1703
1704   \param fmt string format
1705   \param val value
1706   \return formatted value
1707 */
1708 QString QDS_Datum::sprintf( const QString& fmt, const double val )
1709 {
1710   return QString().sprintf( canonicalFormat( fmt ).toLatin1().constData(), val );
1711 }
1712
1713 /*!
1714   \brief Wrapper around the standard sprintf() function.
1715   \overload
1716
1717   Process some non standard flags from format string.
1718
1719   \param fmt string format
1720   \param val value
1721   \return formatted value
1722 */
1723 QString QDS_Datum::sprintf( const QString& fmt, const QString& val )
1724 {
1725   QString aFlags;
1726   QString aFormat = canonicalFormat( fmt, aFlags );
1727
1728   QString txt = val;
1729
1730   QRegExp rx( "^(%[0-9]*.?[0-9]*s)$" );
1731   if ( aFormat.indexOf( rx ) != -1 )
1732   {
1733     // QString().sprintf() always expects string in UTF8 encoding, so we cannot use it here
1734     char* buf = new char[txt.length() + 1];
1735     ::sprintf( buf, aFormat.toLatin1().constData(), (const char*)(txt.toLocal8Bit()) );
1736     txt = QString::fromLocal8Bit( buf );
1737
1738     delete[] buf;
1739   }
1740
1741   if ( isDoubleFormat( aFormat ) )
1742   {
1743     /*bool isOk;
1744     double aVal = txt.toDouble( &isOk );
1745     if ( isOk )
1746     {
1747       txt = sprintf( aFormat, aVal );
1748       txt = txt.replace( 'e', 'D' );
1749     }*/
1750   }
1751
1752   if ( aFlags.contains( "u", Qt::CaseInsensitive ) )
1753     txt = txt.toUpper();
1754   if ( aFlags.contains( "l", Qt::CaseInsensitive ) )
1755     txt = txt.toLower();
1756
1757   return txt;
1758 }
1759
1760 /*!
1761   \brief Get the canonical sprintf() format.
1762   \param fmt string format
1763   \return canonical sprintf() format
1764 */
1765 QString QDS_Datum::canonicalFormat( const QString& fmt )
1766 {
1767   QString flags;
1768   return canonicalFormat( fmt, flags );
1769 }
1770
1771 /*!
1772   \brief Get the canonical sprintf() format and non standard flags.
1773   \param fmt string format
1774   \param flags format flags
1775   \return canonical sprintf() format
1776 */
1777 QString QDS_Datum::canonicalFormat( const QString& fmt, QString& flags )
1778 {
1779   QString newFmt = fmt;
1780   flags = QString();
1781
1782   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]$" );
1783   if ( rx.indexIn( newFmt ) >= 0 )
1784   {
1785     flags = rx.cap( 2 );
1786     newFmt.remove( rx.pos( 2 ), flags.length() );
1787   }
1788   return newFmt;
1789 }
1790
1791 /*!
1792   \brief Get displayable units string for specified data dictionary item.
1793   \param id data dictionary item ID
1794   \return units string
1795 */
1796 QString QDS_Datum::units( const QString& id )
1797 {
1798   QString anUnit;
1799   Handle(DDS_DicItem) anItem;
1800
1801   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
1802   if ( !aDict.IsNull() )
1803   {
1804     anItem = aDict->GetDicItem( toAsciiString( id ) );
1805     if ( !anItem.IsNull() )
1806       anUnit = unitsToText( toQString( anItem->GetUnits() ) );
1807   }
1808   return anUnit;
1809 }
1810
1811 /*!
1812   \brief Get prefix string from format.
1813   \return current implementation returns null string
1814 */
1815 QString QDS_Datum::prefix() const
1816 {
1817   return QString();
1818 }
1819
1820 /*!
1821   \brief Get suffix string from format.
1822   \return current implementation returns null string
1823 */
1824 QString QDS_Datum::suffix() const
1825 {
1826   return QString();
1827 }
1828
1829 /*!
1830   \brief Get minimum value.
1831   \return minimum value
1832 */
1833 QString QDS_Datum::minValue() const
1834 {
1835   QString pref = prefix();
1836   QString suff = suffix();
1837
1838   QString aMin = minimumValue().trimmed();
1839
1840   if ( !pref.isEmpty() && aMin.left( pref.length() ) == pref )
1841     aMin = aMin.mid( pref.length() );
1842
1843   if ( !suff.isEmpty() && aMin.right( suff.length() ) == suff )
1844     aMin = aMin.mid( 0, aMin.length() - suff.length() );
1845
1846   return aMin;
1847 }
1848
1849 /*!
1850   \brief Get maximum value.
1851   \return maximum value
1852 */
1853 QString QDS_Datum::maxValue() const
1854 {
1855   QString pref = prefix();
1856   QString suff = suffix();
1857
1858   QString aMax = maximumValue().trimmed();
1859
1860   if ( !pref.isEmpty() && aMax.left( pref.length() ) == pref )
1861     aMax = aMax.mid( pref.length() );
1862
1863   if ( !suff.isEmpty() && aMax.right( suff.length() ) == suff )
1864     aMax = aMax.mid( 0, aMax.length() - suff.length() );
1865
1866   return aMax;
1867 }
1868
1869 /*!
1870   \brief Reset the numeric value cache.
1871 */
1872 void QDS_Datum::invalidateCache()
1873 {
1874   myTargetValue = QString();
1875 }
1876
1877 /*!
1878   \brief Remove the acceleartor tags '&' from specified label string \a src.
1879   \param src processed string
1880   \return string after removing '&' symbols
1881 */
1882 QString QDS_Datum::removeAccel( const QString& src )
1883 {
1884   QString trg = src;
1885
1886   for ( int i = 0; i < trg.length(); )
1887   {
1888     if ( trg.mid( i, 2 ) == QString( "&&" ) )
1889       i += 2;
1890     else if ( trg.at( i ) == '&' )
1891       trg.remove( i, 1 );
1892     else
1893       i++;
1894   }
1895   return trg;
1896 }
1897
1898 /*!
1899   \brief Check if given format specified doube value.
1900   \param theFormat format string 
1901   \return \c true if \a theFormat has specificator for double values
1902 */
1903 bool QDS_Datum::isDoubleFormat( const QString& theFormat )
1904 {
1905   if ( theFormat.length() > 0 )
1906   {
1907     QChar c = theFormat[ (int)( theFormat.length() - 1 ) ];
1908       return c == 'f' || c == 'g' || c == 'e' || c == 'G' || c == 'E';
1909   }
1910   else
1911     return false;
1912 }
1913
1914 /*!
1915   \brief Get datum flags.
1916   \return datum flags (QDS::DatumFlags)
1917 */
1918 int QDS_Datum::flags() const
1919 {
1920   return myFlags;
1921 }
1922
1923 /*!
1924   \brief Perform initialization if it needed.
1925   \internal
1926 */
1927 void QDS_Datum::initDatum() const
1928 {
1929   if ( myInitialised )
1930     return;
1931
1932   QDS_Datum* that = (QDS_Datum*)this;
1933   that->myInitialised = true;
1934   that->initialize();
1935
1936   if ( parent() )
1937     parent()->removeEventFilter( (QObject*)this );
1938 }
1939
1940 /*!
1941   \brief Get wrapper for specified subwidget.
1942   \internal
1943   \param wid subwidget
1944   \return wrapper
1945 */
1946 QDS_Datum::Wrapper* QDS_Datum::wrapper( QWidget* wid ) const
1947 {
1948   if ( !wid )
1949     return 0;
1950
1951   Wrapper* wrap = 0;
1952   for ( QMap<int, Wrapper*>::ConstIterator it = myWrapper.begin(); it != myWrapper.end() && !wrap; ++it )
1953   {
1954     if ( it.value() && it.value()->widget() == wid )
1955       wrap = it.value();
1956   }
1957   return wrap;
1958 }
1959
1960 /*!
1961   \brief Get wrapper for specified subwidget.
1962   \internal
1963   \param id subwidget ID
1964   \return wrapper
1965 */
1966 QDS_Datum::Wrapper* QDS_Datum::wrapper( const int id ) const
1967 {
1968   Wrapper* wrap = 0;
1969   if ( myWrapper.contains( id ) )
1970     wrap = myWrapper[id];
1971   return wrap;
1972 }
1973
1974 /*!
1975   \brief Get subwidget type for specified wrapper.
1976   \internal
1977   \param wrap wrapper
1978   \return subwidget ID
1979 */
1980 int QDS_Datum::wrapperType( QDS_Datum::Wrapper* wrap ) const
1981 {
1982   int id = -1;
1983   for ( QMap<int, Wrapper*>::ConstIterator it = myWrapper.begin(); it != myWrapper.end() && id == -1; ++it )
1984   {
1985     if ( it.value() == wrap )
1986       id = it.key();
1987   }
1988   return id;
1989 }
1990
1991 /*!
1992   \fn void QDS_Datum::paramChanged();
1993   \brief The signal is emitted when the datum value is changed.
1994 */
1995
1996 /*!
1997   void QDS_Datum::paramChanged( QString& txt );
1998   \brief The signal is emitted when the datum value is changed.
1999   \param txt new datum value
2000 */
2001