Salome HOME
Merge from V6_main (04/10/2012)
[modules/gui.git] / src / QDS / QDS_Datum.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, 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.
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   myLabel( 0 ),
204   myUnits( 0 ),
205   myControl( 0 ),
206   myFlags( flags ),
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   if ( !isEmpty() )
555     val = stringValue();
556   return val;
557 }
558
559 /*!
560   \brief Get the datum value as string.
561   \return datum value converted to string
562 */
563 QString QDS_Datum::stringValue() const
564 {
565   initDatum();
566
567   if ( getString() == myTargetValue )
568     return mySourceValue;
569   else
570     return getString();
571 }
572
573 /*!
574   \brief Get the datum value as double.
575
576   The value is converted according to the measure units in the active units system
577   to measure units in "SI" units system.
578
579   \return datum value converted to double
580 */
581 double QDS_Datum::doubleValue() const
582 {
583   initDatum();
584
585   double res = 0;
586   if ( !myTargetValue.isNull() && myTargetValue == getString() )
587     res = mySourceValue.toDouble();
588   else
589   {
590     res = getString().toDouble();
591     if ( !myDicItem.IsNull() && !( flags() & NotConvert ) )
592       res = myDicItem->ToSI( res );
593   }
594
595   return res;
596 }
597
598 /*!
599   \brief Get the datum value as integer.
600
601   The value is converted according to the measure units in the active units system
602   to measure units in "SI" units system.
603
604   \return datum value converted to integer
605 */
606 int QDS_Datum::integerValue() const
607 {
608   initDatum();
609
610   int res = 0;
611   if ( !myTargetValue.isNull() && myTargetValue == getString() )
612     res = mySourceValue.toInt();
613   else
614   {
615     double val = getString().toDouble();
616     if ( !myDicItem.IsNull() && !( flags() & NotConvert ) )
617       res = (int)myDicItem->ToSI( val );
618   }
619
620   return res;
621 }
622
623 /*!
624   \brief Get the text data from datum.
625
626   Text consists of label, string value and units.
627
628   \return datum text data
629 */
630 QString QDS_Datum::text() const
631 {
632   initDatum();
633
634   QString aLabel = label();
635   QString aData  = stringValue();
636   QString aUnits = units();
637
638   QString res = aLabel;
639   if ( !res.isEmpty() && !aData.isEmpty() )
640     res += QString( ": " );
641
642   res += aData;
643   if ( !aUnits.isEmpty() )
644     res += QString( " " ) + aUnits;
645
646   return res;
647 }
648
649 /*!
650   \brief Check if the datum is empty.
651   \return \c false if datum control has value entered
652 */
653 bool QDS_Datum::isEmpty() const
654 {
655   return stringValue().isEmpty();
656 }
657
658 /*!
659   \brief Reset datum state and set default value as current.
660 */
661 void QDS_Datum::reset()
662 {
663   initDatum();
664
665   mySourceValue = defaultValue();
666   setString( format( ( myFlags & NotFormat ) ? (QString) "" : format(), type(), mySourceValue ) );
667   invalidateCache();
668
669   onParamChanged();
670   QString str = getString();
671   emit paramChanged();
672   emit paramChanged( str );
673 }
674
675 /*!
676   \brief Clear the control.
677 */
678 void QDS_Datum::clear()
679 {
680   initDatum();
681
682   if ( !getString().isEmpty() )
683   {
684     mySourceValue = "";
685     setString( mySourceValue );
686     invalidateCache();
687
688     onParamChanged();
689     QString str = getString();
690     emit paramChanged();
691     emit paramChanged( str );
692   }
693 }
694
695 /*!
696   \brief Set datum value from QVariant object.
697   \param val new value
698 */
699 void QDS_Datum::setValue( const QVariant& val )
700 {
701   if ( val.isValid() && val.canConvert( QVariant::String ) )
702     setStringValue( val.toString() );
703   else
704     clear();
705 }
706
707 /*!
708   \brief Set datum value from string data.
709   \param txt new value
710 */
711 void QDS_Datum::setStringValue( const QString& txt )
712 {
713   initDatum();
714
715   mySourceValue = txt;
716   QString aStr = format( ( flags() & NotFormat ) ? (QString) "" : format(), type(), txt );
717   setString( aStr );
718   myTargetValue = aStr;
719
720   onParamChanged();
721   QString str = getString();
722   emit paramChanged();
723   emit paramChanged( str );
724 }
725
726 /*!
727   \brief Set datum value from double data.
728
729   The value is converted from measure units in "SI" units system
730   to the measure units in the active units system.
731   Format the value using datum format internal if it is required.
732   
733   \param num new value
734 */
735 void QDS_Datum::setDoubleValue( const double num )
736 {
737   initDatum();
738
739   mySourceValue = QString().setNum( num, 'g', 16 );
740   double val = num;
741   if ( !myDicItem.IsNull() && !( flags() & NotConvert ) )
742     val = myDicItem->FromSI( val );
743
744   QString aStr = format( ( flags() & NotFormat ) ? (QString) "" : format(), type(), val );
745   setString( aStr );
746   myTargetValue = aStr;
747
748   onParamChanged();
749   QString str = getString();
750   emit paramChanged();
751   emit paramChanged( str );
752 }
753
754 /*!
755   \brief Set datum value from integer data.
756
757   The value is converted from measure units in "SI" units system
758   to the measure units in the active units system.
759   Format the value using datum format if it is required.
760   
761   \param num new value
762 */
763 void QDS_Datum::setIntegerValue( const int num )
764 {
765   initDatum();
766
767   mySourceValue = QString().setNum( num );
768   double val = num;
769   if ( !myDicItem.IsNull() && !( flags() & NotConvert ) )
770     val = myDicItem->FromSI( val );
771
772   QString aStr = format( ( flags() & NotFormat ) ? (QString) "" : format(), type(), val );
773   setString( aStr );
774   myTargetValue = aStr;
775
776   onParamChanged();
777   QString str = getString();
778   emit paramChanged();
779   emit paramChanged( str );
780 }
781
782 /*!
783   \brief Get 'enabled' state of the specified subwidget.
784   \param element ORed subwidget flags (QDS::DatumFlags)
785   \return \c true if all subwidgets specified by \a element are enabled
786   \sa setEnabled()
787 */
788 bool QDS_Datum::isEnabled( const int element ) const
789 {
790   initDatum();
791
792   bool res = true;
793   if ( element & Label )
794     res = res && labelWidget() && labelWidget()->isEnabled();
795   if ( element & Units )
796     res = res && unitsWidget() && unitsWidget()->isEnabled();
797   if ( element & Control )
798     res = res && controlWidget() && controlWidget()->isEnabled();
799   return res;
800 }
801
802 /*!
803   \brief Enable/disable subwidgets specified by \a element.
804
805   Possible values of \a element: QDS::Label, QDS::Control, QDS::Units
806   or their ORed combinations.
807
808   \param on new 'enabled' state
809   \param element ORed subwidget flags (QDS::DatumFlags)
810   \sa isEnabled()
811 */
812 void QDS_Datum::setEnabled( const bool on, const int element )
813 {
814   initDatum();
815
816   if ( element & Label && labelWidget() )
817     labelWidget()->setEnabled( on );
818   if ( element & Units && unitsWidget() )
819     unitsWidget()->setEnabled( on );
820   if ( element & Control && controlWidget() )
821     controlWidget()->setEnabled( on );
822 }
823
824 /*!
825   \brief Enable/disable main control subwidget (QDS::Control).
826   \param on new 'enabled' state
827 */
828 void QDS_Datum::setEnabled( bool on )
829 {
830   setEnabled( on, Control );
831 }
832
833 /*!
834   \brief Show/hide subwidgets specified by \a flags.
835
836   Possible values of \a flags: QDS::Label, QDS::Control, QDS::Units
837   or their ORed combinations.
838
839   \param visible new 'visibility' state
840   \param flags ORed subwidget flags (QDS::DatumFlags)
841   \sa show(), hide()
842 */
843 void QDS_Datum::setShown( const bool visible, const int flags )
844 {
845   initDatum();
846
847   uint flag = Units;
848   while ( flag )
849   {
850     if ( flags & flag && widget( flag ) )
851       widget( flag )->setShown( visible );
852     flag = flag >> 1;
853   }
854 }
855
856 /*!
857   \brief Show 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 element ORed subwidget flags (QDS::DatumFlags)
863   \sa hide(), setShown()
864 */
865 void QDS_Datum::show( const int element )
866 {
867   setShown( true, element );
868 }
869
870 /*!
871   \brief Hide subwidgets specified by \a element.
872
873   Possible values of \a element: QDS::Label, QDS::Control, QDS::Units
874   or their ORed combinations.
875
876   \param element ORed subwidget flags (QDS::DatumFlags)
877   \sa show(), setShown()
878 */
879 void QDS_Datum::hide( const int element )
880 {
881   setShown( false, element );
882 }
883
884 /*!
885   \brief Get subwidget specified by \a element.
886
887   Possible values of \a element: QDS::Label, QDS::Control, QDS::Units.
888   
889   \param element subwidget
890   \return widget
891 */
892 QWidget* QDS_Datum::widget( const int element ) const
893 {
894   initDatum();
895   return wrapper( element );
896 }
897
898 /*!
899   \brief Set the input focus to the control widget.
900 */
901 void QDS_Datum::setFocus()
902 {
903   initDatum();
904
905   if ( controlWidget() )
906     controlWidget()->setFocus();
907 }
908
909 /*!
910   \brief Check if input data is valid.
911
912   If data is invalid and \a msgBox is \c true, the warning message box is shown.
913
914   \param msgBox if \c true, show warning message box if input is invalid
915   \param extMsg warning message
916   \param extLabel optional name of the variable (if QDS::Label control is not used) 
917   \return \c true if input data is valid
918 */
919 bool QDS_Datum::isValid( const bool msgBox, const QString& extMsg, const QString& extLabel ) const
920 {
921   initDatum();
922
923   if ( type() == DDS_DicItem::String && isDoubleFormat( format() ) )
924     return true;
925
926   QString req;
927   if ( !dicItem().IsNull() )
928     req = toQString( dicItem()->GetRequired() );
929
930   bool aState = true;
931   QString aStr = getString();
932
933   if ( aStr.isEmpty() )
934     aState = !( req == QString( "yes" ) || req == QString( "true" ) || req.toInt() );
935   else
936     aState = validate( aStr );
937
938   if ( msgBox && !aState )
939   {
940     QString info;
941     if ( !label().isEmpty() )
942       info += tr( "DATA_INCORRECT_VALUE" ).arg( label() );
943     else if ( !extLabel.isEmpty() )
944       info += tr( "DATA_INCORRECT_VALUE" ).arg( extLabel );
945
946     QString typeStr;
947     switch ( type() )
948     {
949     case DDS_DicItem::String:
950       typeStr = tr( "DATA_STRING" );
951       break;
952     case DDS_DicItem::Integer:
953       typeStr = tr( "DATA_INTEGER" );
954       break;
955     case DDS_DicItem::Float:
956       typeStr = tr( "DATA_FLOAT" );
957       break;
958     default:
959       typeStr = tr( "DATA_NON_EMPTY" );
960       break;
961     }
962     info += ( info.isEmpty() ? (QString) "" : QString( "\n" ) ) + 
963             tr( "DATA_SHOULD_BE_VALUE" ).arg( typeStr );
964     QString limit;
965     if ( type() == DDS_DicItem::Float || type() == DDS_DicItem::Integer )
966     {
967       QString aMinValue = minValue();
968       QString aMaxValue = maxValue();
969       if ( !aMinValue.isEmpty() && !aMaxValue.isEmpty() )
970         limit = tr( "DATA_RANGE" ).arg( aMinValue ).arg( aMaxValue );
971       else if ( !aMinValue.isEmpty() )
972         limit = tr( "DATA_MIN_LIMIT" ).arg( aMinValue );
973       else if ( !aMaxValue.isEmpty() )
974         limit = tr( "DATA_MAX_LIMIT" ).arg( aMaxValue );
975     }
976     if ( !limit.isEmpty() )
977       info += limit;
978
979     info += QString( ".\n" ) + tr( "DATA_INPUT_VALUE" );
980
981     if ( !extMsg.isEmpty() )
982       info += QString( "\n" ) + extMsg;
983
984     QString msg;
985     for ( int i = 0; i < info.length(); i++ )
986       if ( info.at( i ) == '\n' )
987         msg += QString( "<br>" );
988       else
989         msg += info.at( i );
990
991     info = QString( "<p><nobr>%1</nobr></p>" ).arg( msg );
992
993     QMessageBox::critical( controlWidget() ? controlWidget()->topLevelWidget() : 0,
994                            tr( "DATA_ERR_TITLE" ), info, tr( "OK" ) );
995     if ( controlWidget() )
996       controlWidget()->setFocus();
997   }
998   return aState;
999 }
1000
1001 /*!
1002   \brief Add widgets to the vertical box layout.
1003   \param l layout
1004 */
1005 void QDS_Datum::addTo( QVBoxLayout* l )
1006 {
1007   initDatum();
1008
1009   if ( !l )
1010     return;
1011
1012   if ( wrapper( Label ) )
1013     l->addWidget( wrapper( Label ) );
1014   if ( wrapper( Control ) )
1015     l->addWidget( wrapper( Control ) );
1016   if ( wrapper( Units ) )
1017     l->addWidget( wrapper( Units ) );
1018 }
1019
1020 /*!
1021   \brief Add widgets to the horizontal box layout.
1022   \param l layout
1023 */
1024 void QDS_Datum::addTo( QHBoxLayout* l )
1025 {
1026   initDatum();
1027
1028   if ( !l )
1029     return;
1030
1031   if ( wrapper( Label ) )
1032     l->addWidget( wrapper( Label ) );
1033   if ( wrapper( Control ) )
1034     l->addWidget( wrapper( Control ) );
1035   if ( wrapper( Units ) )
1036     l->addWidget( unitsWidget() );
1037 }
1038
1039 /*!
1040   \brief Add widgets to the grid layout.
1041   \param theLay layout
1042   \param theRow layout row index
1043   \param theCol layout column index
1044   \param vertical if \c true subwidgets are layouted vertically, otherwise - horizontally
1045 */
1046 void QDS_Datum::addTo( QGridLayout* theLay, const int theRow, const int theCol, bool vertical )
1047 {
1048   initDatum();
1049
1050   if ( !theLay )
1051     return;
1052
1053   int row = theRow;
1054   int col = theCol;
1055   if ( wrapper( Label ) )
1056   {
1057     theLay->addWidget( wrapper( Label ), row, col );
1058     vertical ? row++ : col++;
1059   }
1060   if ( wrapper( Control ) )
1061   {
1062     theLay->addWidget( wrapper( Control ), row, col );
1063     vertical ? row++ : col++;
1064   }
1065   if ( wrapper( Units ) )
1066     theLay->addWidget( wrapper( Units ), row, col );
1067 }
1068
1069 /*!
1070   \brief Set the aligment for QDS::Label and/or QDS::Units subwidgets.
1071   \param align alignment type (Qt::Alignment)
1072   \param type ORed subwidget flags
1073 */
1074 void QDS_Datum::setAlignment( const int align, const int type )
1075 {
1076   initDatum();
1077
1078   if ( ( type & Label ) && labelWidget() )
1079     labelWidget()->setAlignment( Qt::Alignment(align) );
1080   if ( ( type & Units ) && unitsWidget() )
1081     unitsWidget()->setAlignment( Qt::Alignment(align) );
1082 }
1083
1084 /*!
1085   \brief Event filter.
1086
1087   Perform delayed initialisation. Reimplemented for internal reasons.
1088   
1089   \param o event reciever object
1090   \param e event
1091   \return \c true if event should be filtered
1092 */
1093 bool QDS_Datum::eventFilter( QObject* o, QEvent* e )
1094 {
1095   if ( o == parent() )
1096   {
1097     if ( e->type() == QEvent::Show || e->type() == QEvent::ShowToParent ||
1098          ( e->type() == QEvent::ChildAdded && ((QChildEvent*)e)->child() == this ) )
1099       initDatum();
1100   }
1101   return QObject::eventFilter( o, e );
1102 }
1103
1104 /*!
1105   \brief Called when datum value is changed.
1106 */
1107 void QDS_Datum::onParamChanged()
1108 {
1109 }
1110
1111 /*!
1112   \brief Perform delayed initialization.
1113 */
1114 void QDS_Datum::onInitDatum()
1115 {
1116   initDatum();
1117 }
1118
1119 /*!
1120   \brief Called when child subwidget is destroued.
1121
1122   Allows avoiding crash of extra calling of the child subwidget destructor.
1123
1124   \param obj object being destroyed
1125 */
1126 void QDS_Datum::onDestroyed( QObject* obj )
1127 {
1128   myWrapper.remove( wrapperType( (Wrapper*)obj ) );
1129 }
1130
1131 /*!
1132   \brief Get QDS::Label widget.
1133   \return label widget
1134 */
1135 QLabel* QDS_Datum::labelWidget() const
1136 {
1137   initDatum();
1138   return myLabel;
1139 }
1140
1141 /*!
1142   \brief Get QDS::Units widget.
1143   \return units widget
1144 */
1145 QLabel* QDS_Datum::unitsWidget() const
1146 {
1147   initDatum();
1148   return myUnits;
1149 }
1150
1151 /*!
1152   \brief Get QDS::Control widget.
1153   \return control widget
1154 */
1155 QWidget* QDS_Datum::controlWidget() const
1156 {
1157   initDatum();
1158   return myControl;
1159 }
1160
1161 /*!
1162   \brief Get the dictionary item from the datum.
1163   \return handle to data dictionary item
1164 */
1165 Handle(DDS_DicItem) QDS_Datum::dicItem() const
1166 {
1167   return myDicItem;
1168 }
1169
1170 /*!
1171   \brief Set the dictionary item to the datum.
1172   \param item handle to data dictionary item
1173 */
1174 void QDS_Datum::setDicItem( const Handle(DDS_DicItem)& item )
1175 {
1176   myDicItem = item;
1177 }
1178
1179 /*!
1180   \brief Create QDS::Label widget.
1181   \param parent parent widget
1182   \return label widget
1183 */
1184 QLabel* QDS_Datum::createLabel( QWidget* parent )
1185 {
1186   return new QLabel( parent );
1187 }
1188
1189 /*!
1190   \brief Create QDS::Units widget.
1191   \param parent parent widget
1192   \return units widget
1193 */
1194 QLabel* QDS_Datum::createUnits( QWidget* parent )
1195 {
1196   return new QLabel( parent );
1197 }
1198
1199 /*!
1200   \fn QWidget* QDS_Datum::createControl( QWidget* parent );
1201   \brief Create QDS::Control widget.
1202
1203   This method should be implemented in the successor classes.
1204
1205   \param parent parent widget
1206   \return control widget
1207 */
1208
1209 /*!
1210   \fn QString QDS_Datum::getString() const;
1211   \brief Get string value from datum.
1212   
1213   This method should be implemented in the successor classes.
1214   
1215   \return datum string value
1216 */
1217
1218 /*
1219   \fn void QDS_Datum::setString( const QString& txt );
1220   \brief Set string value to datum.
1221   
1222   This method should be implemented in the successor classes.
1223   
1224   \param txt new datum string value
1225 */
1226
1227 /*!
1228   \brief Create validator according to the datum type of value.
1229   \param limits if \c true use minimum and maximum value limits
1230   \return validator
1231 */
1232 QValidator* QDS_Datum::validator( const bool limits ) const
1233 {
1234   QValidator* aValidator = 0;
1235
1236   QString fltr = filter();
1237
1238   if ( type() == DDS_DicItem::String )
1239   {
1240     QString aFlags;
1241     QString aFormat = canonicalFormat( format(), aFlags );
1242
1243     int len = -1;
1244     int pos = aFormat.indexOf( "." );
1245     if ( pos != -1 )
1246     {
1247       QString numStr = aFormat.mid( pos + 1, aFormat.length() - pos - 2 );
1248       bool ok;
1249       int numVal = numStr.toInt( &ok );
1250       if ( ok )
1251         len = numVal;
1252     }
1253
1254     QDS_StringValidator* aStrVal = new QDS_StringValidator( fltr, aFlags, (QObject*)this );
1255     aStrVal->setLength( len );
1256
1257     aValidator = aStrVal;
1258   }
1259   else if ( type() == DDS_DicItem::Integer )
1260   {
1261     QDS_IntegerValidator* aIntVal = new QDS_IntegerValidator( fltr, (QObject*)this );
1262
1263     bool ok;
1264     int limit;
1265     limit = minValue().toInt( &ok );
1266     if ( ok && limits )
1267       aIntVal->setBottom( limit );
1268     limit = maxValue().toInt( &ok );
1269     if ( ok && limits )
1270       aIntVal->setTop( limit );
1271
1272     aValidator = aIntVal;
1273   }
1274   else if ( type() == DDS_DicItem::Float )
1275   {
1276     QDS_DoubleValidator* aFloatVal = new QDS_DoubleValidator( fltr, (QObject*)this );
1277
1278     bool ok;
1279     double limit;
1280     limit = minValue().toDouble( &ok );
1281     if ( ok && limits )
1282       aFloatVal->setBottom( limit );
1283     limit = maxValue().toDouble( &ok );
1284     if ( ok && limits )
1285       aFloatVal->setTop( limit );
1286
1287     aValidator = aFloatVal;
1288   }
1289
1290   return aValidator;
1291 }
1292
1293 /*!
1294   \brief Validate the specified string.
1295   \param txt string to be validated
1296   \return \c true if string contains valid data
1297 */
1298 bool QDS_Datum::validate( const QString& txt ) const
1299 {
1300   if ( type() == DDS_DicItem::Unknown ||
1301        ( type() == DDS_DicItem::String && isDoubleFormat( format() ) ) )
1302     return true;
1303
1304   QValidator* aValidator = validator( true );
1305
1306   if ( !aValidator )
1307     return true;
1308
1309   int pos = 0;
1310   QString str( txt );
1311   bool res = aValidator->validate( str, pos ) == QValidator::Acceptable;
1312
1313   delete aValidator;
1314
1315   return res;
1316 }
1317
1318 /*!
1319   \brief Initialize datum.
1320   
1321   Retrieve information from data dictionary and create subwidgets
1322   using virtual mechanism.
1323
1324   Virtual mechanism doesn't work in the constructor, therefore this method should
1325   be called outside the constructor.
1326 */
1327 void QDS_Datum::initialize()
1328 {
1329   if ( wrapper( Label ) )
1330     wrapper( Label )->setWidget( myLabel = createLabel( wrapper( Label ) ) );
1331   if ( wrapper( Control ) )
1332     wrapper( Control )->setWidget( myControl = createControl( wrapper( Control ) ) );
1333   if ( wrapper( Units ) )
1334     wrapper( Units )->setWidget( myUnits = createUnits( wrapper( Units ) ) );
1335
1336   TCollection_AsciiString comp;
1337   Handle(DDS_DicItem) item = dicItem();
1338   if ( !item.IsNull() )
1339     comp = item->GetComponent();
1340
1341   QString unitSystem;
1342   Handle(DDS_Dictionary) dic = DDS_Dictionary::Get();
1343   if ( !dic.IsNull() )
1344     unitSystem = toQString( comp.IsEmpty() ? dic->GetActiveUnitSystem() :
1345                                              dic->GetActiveUnitSystem( comp ) );
1346
1347   unitSystemChanged( unitSystem );
1348
1349   QWidget* ctrl = controlWidget();
1350   if ( ctrl )
1351   {
1352     QString lDescr = longDescription();
1353     QString sDescr = shortDescription();
1354     if ( !sDescr.isEmpty() )
1355       ctrl->setToolTip( sDescr );
1356     if ( !lDescr.isEmpty() )
1357       ctrl->setWhatsThis( lDescr );
1358   }
1359
1360   if ( labelWidget() && ctrl && !( flags() & NotAccel ) )
1361     labelWidget()->setBuddy( ctrl );
1362 }
1363
1364 /*!
1365   \brief Process notification about active units system changing.
1366   
1367   Update label and units widgets.
1368
1369   \param unitSystem new active units system
1370 */
1371 void QDS_Datum::unitSystemChanged( const QString& unitSystem )
1372 {
1373   QString labText = label();
1374   QString unitText = unitsToText( units() );
1375
1376   if ( flags() & UnitsWithLabel )
1377   {
1378     if ( labText.isEmpty() )
1379       labText = unitText;
1380     else if ( !unitText.isEmpty() )
1381       labText = QString( "%1 (%2)" ).arg( labText ).arg( unitText );
1382     unitText = QString();
1383   }
1384
1385   if ( labelWidget() )
1386     labelWidget()->setText( labText );
1387
1388   if ( unitsWidget() )
1389     unitsWidget()->setText( unitText );
1390
1391   reset();
1392 }
1393
1394 /*!
1395   \brief Convert units into text presentation.
1396   \param uni units to be converted
1397   \return text presentation of units (rich-text)
1398 */
1399 QString QDS_Datum::unitsToText( const QString& uni )
1400 {
1401   int pos = -1;
1402   QString aUnits = uni;
1403   while ( ( pos = aUnits.indexOf( "**" ) ) != -1 )
1404   {
1405     aUnits = aUnits.mid( 0, pos ) + QString( "<tt><font size=+2><sup>" ) +
1406              aUnits.mid( pos + 2, 1 ) + QString( "</sup></font></tt>" ) +
1407              aUnits.mid( pos + 3 );
1408   }
1409   return aUnits;
1410 }
1411
1412 /*!
1413   \brief Convert text presentation into internal units format.
1414   \param txt text presentation of units (rich-text)
1415   \return units value
1416 */
1417 QString QDS_Datum::textToUnits( const QString& txt )
1418 {
1419   int pos = -1;
1420   QString aUnits = txt;
1421   while ( ( pos = aUnits.indexOf( "<sup>" ) ) != -1 )
1422   {
1423     aUnits.remove( pos, 5 );
1424     aUnits.insert( pos, "**" );
1425   }
1426   while ( ( pos = aUnits.indexOf( "</sup>" ) ) != -1 )
1427     aUnits.remove( pos, 6 );
1428   return aUnits;
1429 }
1430
1431 /*!
1432   \brief Format the specified integer as dictionary item value.
1433   \param num integer value being formatted
1434   \param id data dictionary ID
1435   \param convert if \c true, perform conversion from "SI" units system
1436   \return formatted value
1437 */
1438 QString QDS_Datum::format( const int num, const QString& id, const bool convert )
1439 {
1440   Handle(DDS_DicItem) anItem;
1441   int aNum = num;
1442   QString anUnit;
1443   
1444   QString aFormat;
1445   int aType = DDS_DicItem::Unknown;
1446   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
1447   if ( !aDict.IsNull() )
1448   {
1449     anItem = aDict->GetDicItem( toAsciiString( id ) );
1450     if ( !anItem.IsNull() )
1451     {
1452       aType = anItem->GetType();
1453       aFormat = toQString( anItem->GetFormat( false ) );
1454       if ( convert )
1455         aNum = ( int )anItem->FromSI( aNum );
1456     }
1457   }
1458
1459   return format( aFormat, aType, aNum );
1460 }
1461
1462 /*!
1463   \brief Format the specified double as dictionary item value.
1464   \param num double value being formatted
1465   \param id data dictionary ID
1466   \param convert if \c true, perform conversion from "SI" units system
1467   \return formatted value
1468 */
1469 QString QDS_Datum::format( const double num, const QString& id, const bool convert )
1470 {
1471   Handle(DDS_DicItem) anItem;
1472   double aNum = num;
1473   QString anUnit;
1474   
1475   QString aFormat;
1476   int aType = DDS_DicItem::Unknown;
1477   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
1478   if ( !aDict.IsNull() )
1479   {
1480     anItem = aDict->GetDicItem( toAsciiString( id ) );
1481     if ( !anItem.IsNull() )
1482     {
1483       aType = anItem->GetType();
1484       aFormat = toQString( anItem->GetFormat( false ) );
1485       if ( convert )
1486         aNum = anItem->FromSI( aNum );
1487     }
1488   }
1489
1490   return format( aFormat, aType, aNum );
1491 }
1492
1493 /*!
1494   \brief Format the specified string as dictionary item value.
1495   \param str string value being formatted
1496   \param id data dictionary ID
1497   \param convert if \c true, perform conversion from "SI" units system
1498   \return formatted value
1499 */
1500 QString QDS_Datum::format( const QString& str, const QString& id, const bool convert )
1501 {
1502   Handle(DDS_DicItem) anItem;
1503   QString aStr = str;
1504   QString anUnit;
1505
1506   QString aFormat;
1507   int aType = DDS_DicItem::Unknown;
1508   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
1509   if ( !aDict.IsNull() )
1510   {
1511     anItem = aDict->GetDicItem( toAsciiString( id ) );
1512     if ( !anItem.IsNull() )
1513     {
1514       aType = anItem->GetType();
1515       aFormat = toQString( anItem->GetFormat( false ) );
1516       if ( convert )
1517         aStr = QString::number( anItem->FromSI( aStr.toDouble() ), 'f', 16 );
1518     }
1519   }
1520
1521   return format( aFormat, aType, aStr );
1522 }
1523
1524 /*!
1525   \brief Format the given value according to the data dictionary item type.
1526   \param aFormat format string
1527   \param aType data dictionary item type
1528   \param aValue integer value being formatted
1529   \return formatted value
1530 */
1531 QString QDS_Datum::format( const QString& aFormat, const int aType, const int aValue )
1532 {
1533   QString txt;
1534
1535   if ( !aFormat.isEmpty() )
1536   {
1537     switch ( aType )
1538     {
1539     case DDS_DicItem::Float:
1540       txt = sprintf( aFormat, (double)aValue );
1541       txt = txt.trimmed();
1542       break;
1543     case DDS_DicItem::Integer:
1544       txt = sprintf( aFormat, aValue );
1545       txt = txt.trimmed();
1546       break;
1547     case DDS_DicItem::String:
1548     default:
1549       txt = sprintf( aFormat, aValue );
1550       break;
1551     }
1552   }
1553   else
1554     txt = QString().setNum( aValue );
1555
1556   return txt;
1557 }
1558
1559 /*!
1560   \brief Format the given value according to the data dictionary item type.
1561   \param aFormat format string
1562   \param aType data dictionary item type
1563   \param aValue double value being formatted
1564   \return formatted value
1565 */
1566 QString QDS_Datum::format( const QString& aFormat, const int aType, const double aValue )
1567 {
1568   QString txt;
1569
1570   if ( !aFormat.isEmpty() )
1571   {
1572     switch ( aType )
1573     {
1574     case DDS_DicItem::Float:
1575       txt = QString().sprintf( aFormat.toLatin1().constData(), aValue );
1576       txt = txt.trimmed();
1577       break;
1578     case DDS_DicItem::Integer:
1579       txt = QString().sprintf( aFormat.toLatin1().constData(), (int)aValue );
1580       txt = txt.trimmed();
1581       break;
1582     case DDS_DicItem::String:
1583     default:
1584       txt = QString().sprintf( aFormat.toLatin1().constData(), aValue );
1585       break;
1586     }
1587   }
1588   else
1589     txt = QString().setNum( aValue, 'g', 16 );
1590
1591   return txt;
1592 }
1593
1594 /*!
1595   \brief Format the given value according to the data dictionary item type.
1596   \param aFormat format string
1597   \param aType data dictionary item type
1598   \param aValue string value being formatted
1599   \return formatted value
1600 */
1601 QString QDS_Datum::format( const QString& aFormat, const int aType, const QString& aValue )
1602 {
1603   QString txt = aValue;
1604
1605   if ( aType != DDS_DicItem::String )
1606     txt = txt.trimmed();
1607
1608   if ( aFormat.isEmpty() || txt.isEmpty() )
1609     return txt;
1610
1611   switch ( aType )
1612   {
1613   case DDS_DicItem::Float:
1614     txt = txt.replace( 'd', 'e' ).replace( 'D', 'E' );
1615     txt = sprintf( aFormat, txt.toDouble() );
1616     txt = txt.trimmed();
1617     break;
1618   case DDS_DicItem::Integer:
1619     txt = sprintf( aFormat, txt.toInt() );
1620     txt = txt.trimmed();
1621     break;
1622   case DDS_DicItem::String:
1623     txt = sprintf( aFormat, txt );
1624     break;
1625   }
1626
1627   return txt;
1628 }
1629
1630 /*!
1631   \brief Wrapper around the standard sprintf() function.
1632
1633   Process some non standard flags from format string.
1634
1635   \param fmt string format
1636   \param val value
1637   \return formatted value
1638 */
1639 QString QDS_Datum::sprintf( const QString& fmt, const int val )
1640 {
1641   return QString().sprintf( canonicalFormat( fmt ).toLatin1().constData(), val );
1642 }
1643
1644 /*!
1645   \brief Wrapper around the standard sprintf() function.
1646   \overload
1647
1648   Process some non standard flags from format string.
1649
1650   \param fmt string format
1651   \param val value
1652   \return formatted value
1653 */
1654 QString QDS_Datum::sprintf( const QString& fmt, const double val )
1655 {
1656   return QString().sprintf( canonicalFormat( fmt ).toLatin1().constData(), val );
1657 }
1658
1659 /*!
1660   \brief Wrapper around the standard sprintf() function.
1661   \overload
1662
1663   Process some non standard flags from format string.
1664
1665   \param fmt string format
1666   \param val value
1667   \return formatted value
1668 */
1669 QString QDS_Datum::sprintf( const QString& fmt, const QString& val )
1670 {
1671   QString aFlags;
1672   QString aFormat = canonicalFormat( fmt, aFlags );
1673
1674   QString txt = val;
1675
1676   QRegExp rx( "^(%[0-9]*.?[0-9]*s)$" );
1677   if ( aFormat.indexOf( rx ) != -1 )
1678   {
1679     // QString().sprintf() always expects string in UTF8 encoding, so we cannot use it here
1680     char* buf = new char[txt.length() + 1];
1681     ::sprintf( buf, aFormat.toLatin1().constData(), (const char*)(txt.toLocal8Bit()) );
1682     txt = QString::fromLocal8Bit( buf );
1683
1684     delete[] buf;
1685   }
1686
1687   if ( isDoubleFormat( aFormat ) )
1688   {
1689     /*bool isOk;
1690     double aVal = txt.toDouble( &isOk );
1691     if ( isOk )
1692     {
1693       txt = sprintf( aFormat, aVal );
1694       txt = txt.replace( 'e', 'D' );
1695     }*/
1696   }
1697
1698   if ( aFlags.contains( "u", Qt::CaseInsensitive ) )
1699     txt = txt.toUpper();
1700   if ( aFlags.contains( "l", Qt::CaseInsensitive ) )
1701     txt = txt.toLower();
1702
1703   return txt;
1704 }
1705
1706 /*!
1707   \brief Get the canonical sprintf() format.
1708   \param fmt string format
1709   \return canonical sprintf() format
1710 */
1711 QString QDS_Datum::canonicalFormat( const QString& fmt )
1712 {
1713   QString flags;
1714   return canonicalFormat( fmt, flags );
1715 }
1716
1717 /*!
1718   \brief Get the canonical sprintf() format and non standard flags.
1719   \param fmt string format
1720   \param flags format flags
1721   \return canonical sprintf() format
1722 */
1723 QString QDS_Datum::canonicalFormat( const QString& fmt, QString& flags )
1724 {
1725   QString newFmt = fmt;
1726   flags = QString();
1727
1728   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]$" );
1729   if ( rx.indexIn( newFmt ) >= 0 )
1730   {
1731     flags = rx.cap( 2 );
1732     newFmt.remove( rx.pos( 2 ), flags.length() );
1733   }
1734   return newFmt;
1735 }
1736
1737 /*!
1738   \brief Get displayable units string for specified data dictionary item.
1739   \param id data dictionary item ID
1740   \return units string
1741 */
1742 QString QDS_Datum::units( const QString& id )
1743 {
1744   QString anUnit;
1745   Handle(DDS_DicItem) anItem;
1746
1747   Handle(DDS_Dictionary) aDict = DDS_Dictionary::Get();
1748   if ( !aDict.IsNull() )
1749   {
1750     anItem = aDict->GetDicItem( toAsciiString( id ) );
1751     if ( !anItem.IsNull() )
1752       anUnit = unitsToText( toQString( anItem->GetUnits() ) );
1753   }
1754   return anUnit;
1755 }
1756
1757 /*!
1758   \brief Get prefix string from format.
1759   \return current implementation returns null string
1760 */
1761 QString QDS_Datum::prefix() const
1762 {
1763   return QString();
1764 }
1765
1766 /*!
1767   \brief Get suffix string from format.
1768   \return current implementation returns null string
1769 */
1770 QString QDS_Datum::suffix() const
1771 {
1772   return QString();
1773 }
1774
1775 /*!
1776   \brief Get minimum value.
1777   \return minimum value
1778 */
1779 QString QDS_Datum::minValue() const
1780 {
1781   QString pref = prefix();
1782   QString suff = suffix();
1783
1784   QString aMin = minimumValue().trimmed();
1785
1786   if ( !pref.isEmpty() && aMin.left( pref.length() ) == pref )
1787     aMin = aMin.mid( pref.length() );
1788
1789   if ( !suff.isEmpty() && aMin.right( suff.length() ) == suff )
1790     aMin = aMin.mid( 0, aMin.length() - suff.length() );
1791
1792   return aMin;
1793 }
1794
1795 /*!
1796   \brief Get maximum value.
1797   \return maximum value
1798 */
1799 QString QDS_Datum::maxValue() const
1800 {
1801   QString pref = prefix();
1802   QString suff = suffix();
1803
1804   QString aMax = maximumValue().trimmed();
1805
1806   if ( !pref.isEmpty() && aMax.left( pref.length() ) == pref )
1807     aMax = aMax.mid( pref.length() );
1808
1809   if ( !suff.isEmpty() && aMax.right( suff.length() ) == suff )
1810     aMax = aMax.mid( 0, aMax.length() - suff.length() );
1811
1812   return aMax;
1813 }
1814
1815 /*!
1816   \brief Reset the numeric value cache.
1817 */
1818 void QDS_Datum::invalidateCache()
1819 {
1820   myTargetValue = QString();
1821 }
1822
1823 /*!
1824   \brief Remove the acceleartor tags '&' from specified label string \a src.
1825   \param src processed string
1826   \return string after removing '&' symbols
1827 */
1828 QString QDS_Datum::removeAccel( const QString& src )
1829 {
1830   QString trg = src;
1831
1832   for ( uint i = 0; i < trg.length(); )
1833   {
1834     if ( trg.mid( i, 2 ) == QString( "&&" ) )
1835       i += 2;
1836     else if ( trg.at( i ) == '&' )
1837       trg.remove( i, 1 );
1838     else
1839       i++;
1840   }
1841   return trg;
1842 }
1843
1844 /*!
1845   \brief Check if given format specified doube value.
1846   \param theFormat format string 
1847   \return \c true if \a theFormat has specificator for double values
1848 */
1849 bool QDS_Datum::isDoubleFormat( const QString& theFormat )
1850 {
1851   if ( theFormat.length() > 0 )
1852   {
1853     QChar c = theFormat[ (int)( theFormat.length() - 1 ) ];
1854       return c == 'f' || c == 'g' || c == 'e' || c == 'G' || c == 'E';
1855   }
1856   else
1857     return false;
1858 }
1859
1860 /*!
1861   \brief Get datum flags.
1862   \return datum flags (QDS::DatumFlags)
1863 */
1864 int QDS_Datum::flags() const
1865 {
1866   return myFlags;
1867 }
1868
1869 /*!
1870   \brief Perform initialization if it needed.
1871   \internal
1872 */
1873 void QDS_Datum::initDatum() const
1874 {
1875   if ( myInitialised )
1876     return;
1877
1878   QDS_Datum* that = (QDS_Datum*)this;
1879   that->myInitialised = true;
1880   that->initialize();
1881
1882   if ( parent() )
1883     parent()->removeEventFilter( (QObject*)this );
1884 }
1885
1886 /*!
1887   \brief Get wrapper for specified subwidget.
1888   \internal
1889   \param wid subwidget
1890   \return wrapper
1891 */
1892 QDS_Datum::Wrapper* QDS_Datum::wrapper( QWidget* wid ) const
1893 {
1894   if ( !wid )
1895     return 0;
1896
1897   Wrapper* wrap = 0;
1898   for ( QMap<int, Wrapper*>::ConstIterator it = myWrapper.begin(); it != myWrapper.end() && !wrap; ++it )
1899   {
1900     if ( it.value() && it.value()->widget() == wid )
1901       wrap = it.value();
1902   }
1903   return wrap;
1904 }
1905
1906 /*!
1907   \brief Get wrapper for specified subwidget.
1908   \internal
1909   \param id subwidget ID
1910   \return wrapper
1911 */
1912 QDS_Datum::Wrapper* QDS_Datum::wrapper( const int id ) const
1913 {
1914   Wrapper* wrap = 0;
1915   if ( myWrapper.contains( id ) )
1916     wrap = myWrapper[id];
1917   return wrap;
1918 }
1919
1920 /*!
1921   \brief Get subwidget type for specified wrapper.
1922   \internal
1923   \param wrap wrapper
1924   \return subwidget ID
1925 */
1926 int QDS_Datum::wrapperType( QDS_Datum::Wrapper* wrap ) const
1927 {
1928   int id = -1;
1929   for ( QMap<int, Wrapper*>::ConstIterator it = myWrapper.begin(); it != myWrapper.end() && id == -1; ++it )
1930   {
1931     if ( it.value() == wrap )
1932       id = it.key();
1933   }
1934   return id;
1935 }
1936
1937 /*!
1938   \fn void QDS_Datum::paramChanged();
1939   \brief The signal is emitted when the datum value is changed.
1940 */
1941
1942 /*!
1943   void QDS_Datum::paramChanged( QString& txt );
1944   \brief The signal is emitted when the datum value is changed.
1945   \param txt new datum value
1946 */
1947