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