Salome HOME
e7c2890272e98192e327af81eae9a4b527247e8f
[modules/gui.git] / src / QDS / QDS_ComboBox.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_ComboBox.h"
23
24 #include <QtxComboBox.h>
25
26 #include <TColStd_HArray1OfInteger.hxx>
27 #include <TColStd_HArray1OfExtendedString.hxx>
28
29 #include <QLineEdit>
30
31 /*
32   \class QDS_ComboBox
33   
34   \brief Datum with control corresponding to the combo box. 
35
36   This control is used for datum with enumerable values.
37   It can be used for datum which has type of value 'List'. 
38
39   Each item of the combobox is defined by two properties: integer identifier 
40   and string name. All operations on items are performed via identifier.
41 */
42
43 /*!
44   \brief Constructor. 
45
46   Create combobox datum object with datum identifier \a id 
47   and parent widget \a parent. 
48
49   Parameter \a flags defines behaviour of datum and set of created
50   subwidgets. Default value of this parameter is QDS::All.
51
52   Parameter \a comp specifies the component name which will be used
53   when searching the dictionary item.
54
55   \param id datum identifier
56   \param parent parent widget
57   \param flags datum flags
58   \param comp component
59 */
60 QDS_ComboBox::QDS_ComboBox( const QString& id, QWidget* parent, const int flags, const QString& comp )
61 : QDS_Datum( id, parent, flags, comp )
62 {
63 }
64
65 /*!
66   \brief Destructor.
67 */
68 QDS_ComboBox::~QDS_ComboBox()
69 {
70 }
71
72 /*!
73   \brief Check if combo box allows text editing.
74   \return \c true if combo box is editable
75 */
76 bool QDS_ComboBox::editable() const
77 {
78   if ( comboBox() && comboBox()->lineEdit() )
79     return !comboBox()->lineEdit()->isReadOnly();
80   else
81     return false;
82 }
83
84 /*!
85   \brief Enable/disable text editing.
86   \param on if \c true, combo box is made editable
87 */
88 void QDS_ComboBox::setEditable( const bool on )
89 {
90   QComboBox* aCombo = comboBox();
91   if ( aCombo )
92     aCombo->setEditable( on );
93   if ( aCombo && aCombo->lineEdit() )
94   {
95     aCombo->lineEdit()->setReadOnly( !on );
96     aCombo->setValidator(0);
97     if ( on )
98       aCombo->setValidator( validator() );
99   }
100 }
101
102 /*!
103   \brief Get number of items in the combo box.
104
105   \param total if \c false, only visible items are taken into account, 
106         otherwise get total number of items
107   \return number of items
108 */
109 int QDS_ComboBox::count( bool total ) const
110 {
111   if ( total )
112     return myValue.count();
113   else if ( comboBox() )
114     return comboBox()->count();
115   else
116     return 0;
117 }
118
119 /*!
120   \brief Get items identifiers.
121
122   \param ids returned list of items IDs
123   \param total if \c false, only visible items are taken into account, 
124         otherwise get total number of items
125 */
126 void QDS_ComboBox::values( QList<int>& ids, bool total ) const
127 {
128   ids.clear();
129   for ( QIntList::const_iterator it = myDataIds.begin(); it != myDataIds.end(); ++it )
130     if ( total || ( myState.contains( *it ) && myState[*it] ) )
131       ids.append( *it );
132 }
133
134 /*!
135   \brief Get the current item ID as integer value.
136   \return current item ID converted to integer
137 */
138 int QDS_ComboBox::integerValue() const
139 {
140   QComboBox* cb = comboBox();
141   QString cur = getString();
142   if ( cb && cb->count() > 0 && cb->currentIndex() >= 0 )
143     cur = cb->itemText( cb->currentIndex() );
144
145   if ( cb && cur == getString() )
146     return getId( cb->currentIndex() );
147   else
148     return getId( getString() );
149 }
150
151 /*!
152   \brief Get the current item ID as double value.
153   \return current item ID converted to double
154 */
155 double QDS_ComboBox::doubleValue() const
156 {
157   initDatum();
158
159   QComboBox* cb = comboBox();
160   QString cur = getString();
161   if ( cb && cb->count() > 0 && cb->currentIndex() >= 0 )
162     cur = cb->itemText( cb->currentIndex() );
163
164   if ( cb && cur == getString() )
165     return getId( cb->currentIndex() );
166   else
167     return getId( getString() );
168 }
169
170 /*!
171   \brief Set the current item acording to the specified \a id.
172   \param id item ID
173 */
174 void QDS_ComboBox::setIntegerValue( const int id )
175 {
176   initDatum();
177
178   if ( myValue.contains( id ) )
179     setString( myValue[id] );
180   else 
181     setString( "" );
182 }
183
184 /*!
185   \brief Set the current item acording to the specified \a id.
186   \overload
187
188   Integer part of \a val is used as new current ID.
189   
190   \param val item ID
191 */
192 void QDS_ComboBox::setDoubleValue( const double val )
193 {
194   initDatum();
195
196   int id = (int)val;
197   if ( myValue.contains( id ) )
198     setString( myValue[id] );
199   else if ( id == -1 )
200     setString( "" );
201 }
202
203 /*!
204   \brief Get visibility state of the item specified by \a id.
205   \param id item ID
206   \return item visibility state
207 */
208 bool QDS_ComboBox::state( const int id ) const
209 {
210   bool state = false;
211   if ( myState.contains( id ) )
212     state = myState[id];
213   return state;
214 }
215
216 /*!
217   \brief Set the visibility state of the item specified by \a id.
218
219   If \a id is -1 then specified state will be set to all items.
220
221   If \a append is set to \c true, keep current status for other items,
222   otherwise status of other items is cleared.
223
224   \param on new visibility state
225   \param id item ID
226   \param append if \c true, keep original status for other items
227 */
228 void QDS_ComboBox::setState( const bool on, const int id, const bool append )
229 {
230   QList<int> lst;
231   if ( id < 0 )
232   {
233     for ( IdStateMap::Iterator it = myState.begin(); it != myState.end(); ++it )
234       lst.append( it.key() );
235   }
236   else
237     lst.append( id );
238
239   setState( on, lst, append );
240 }
241
242 /*!
243   \brief Set the visibility state of items specified by \a ids.
244
245   If \a append is set to \c true, keep current status for other items,
246   otherwise status of other items is cleared.
247
248   \param on new visibility state
249   \param ids items IDs list
250   \param append if \c true, keep original status for other items
251 */
252 void QDS_ComboBox::setState( const bool on, const QList<int>& ids, const bool append )
253 {
254   initDatum();
255
256   if ( ids.isEmpty() && append )
257     return;
258
259   bool changed = false;
260
261   QMap<int, int> aMap;
262   for ( uint i = 0; i < ids.count(); i++ )
263     aMap.insert( ids.at( i ), 0 );
264
265   for ( IdStateMap::Iterator it = myState.begin(); it != myState.end(); ++it )
266   {
267     if ( aMap.contains( it.key() ) )
268     {
269       if ( it.value() != on )
270       {
271         it.value() = on;
272         changed = true;
273       }
274     }
275     else if ( !append && it.value() == on )
276     {
277       it.value() = !on;
278       changed = true;
279     }
280   }
281   if ( changed )
282     updateComboBox();
283 }
284
285 /*!
286   \brief Set the custom user items into the combo box.
287
288   User items like standard dictionary list items will be added
289   into the combobox. This function allows user to override
290   items.
291
292   \param ids items IDs
293   \param names items names
294 */
295 void QDS_ComboBox::setValues( const QList<int>& ids, const QStringList& names )
296 {
297   initDatum();
298
299   if ( ids.count() != names.count() )
300     return;
301
302   myUserIds = ids;
303   myUserNames = names;
304
305   unitSystemChanged( "" );
306 }
307
308 /*!
309   \brief Set the custom user items into the combo box.
310   \overload
311
312   User items like standard dictionary list items will be added
313   into the combobox. This function allows user to override
314   items.
315
316   Uses (0, 1, 2 ... ) as items IDs.
317
318   \param names items names
319 */
320 void QDS_ComboBox::setValues( const QStringList& names )
321 {
322   initDatum();
323
324   QList< int > ids;
325   for ( int i = 0, n = names.count(); i < n; i++ )
326     ids.append( i );
327   setValues( ids, names );
328 }
329
330 /*!
331   \brief Reset the datum.
332
333   Set the active item as item with default ID. If default ID is not defined
334   then the first item is used.
335 */
336 void QDS_ComboBox::reset()
337 {
338   int id = -1;
339   QString aDefValue = defaultValue();
340   if ( !aDefValue.isEmpty() )
341     setString( aDefValue );
342   else
343     setIntegerValue( getId( 0 ) );
344 }
345
346 /*!
347   \brief Convert string to integer value.
348   \param str item
349   \return item ID or -1 if not found
350 */
351 int QDS_ComboBox::stringToValue( const QString& str ) const
352 {
353   return getId( str );
354 }
355
356 /*!
357   \brief Convert integer to string value.
358   \param val item ID 
359   \return item value or empty string if \c val is invalid
360 */
361 QString QDS_ComboBox::valueToString( const int val ) const
362 {
363   QString str;
364   if ( myValue.contains( val ) )
365     str = myValue[val];
366   return str;
367 }
368
369 /*!
370   \brief Get string from the combo box.
371   \return string value
372 */
373 QString QDS_ComboBox::getString() const
374 {
375   QString res;
376   QtxComboBox* cb = comboBox();
377   if ( cb )
378   {
379     if ( !cb->isEditable() )
380     {
381       if ( !cb->isCleared() )
382         res = cb->currentText(); 
383     }
384     else
385       res = cb->lineEdit()->text();
386   }
387   return res;
388 }
389
390 /*!
391   \brief Set the string value to the combo box widget.
392   \param txt string value
393 */
394 void QDS_ComboBox::setString( const QString& txt )
395 {
396   QtxComboBox* cb = comboBox();
397   if ( !cb )
398     return;
399
400   bool isClear = cb->isCleared();
401   
402   int idx = -1;
403   for ( int i = 0; i < cb->count() && idx == -1; i++ )
404     if ( cb->itemText( i ) == txt )
405       idx = i;
406
407   int old = cb->currentIndex();
408   if ( idx != -1 )
409     cb->setCurrentIndex( idx );
410   else if ( txt.isEmpty() )
411   {
412     if ( !cb->isEditable() )
413       cb->setItemText( cb->currentIndex(), txt );
414     else
415       cb->lineEdit()->setText( txt );
416   }
417   if ( isClear != txt.isEmpty() || ( !isClear && old != cb->currentIndex() ) )
418   {
419     onParamChanged();
420     QString str = getString();
421     emit activated( integerValue() );
422     emit activated( str );
423     emit paramChanged();
424     emit paramChanged( str );
425   }
426 }
427
428 /*!
429   \brief Get combo box widget.
430   \return internal combo box widget
431 */
432 QtxComboBox* QDS_ComboBox::comboBox() const
433 {
434   return ::qobject_cast<QtxComboBox*>( controlWidget() );
435 }
436
437 /*!
438   \brief Create internal combo box as control widget.
439   \param parent parent widget
440   \return created combo box widget
441 */
442 QWidget* QDS_ComboBox::createControl( QWidget* parent )
443 {
444   QtxComboBox* cb = new QtxComboBox( parent );
445   cb->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed ) );
446   connect( cb, SIGNAL( textChanged( const QString& ) ), this,
447            SLOT( onTextChanged( const QString& ) ) );
448   connect( cb, SIGNAL( activated( int ) ), this, SLOT( onActivated( int ) ) );
449   return cb;
450 }
451
452 /*!
453   \brief Process notification about active units system changing.
454
455   Update combobox contents.
456   
457   \param system new active units system
458 */
459 void QDS_ComboBox::unitSystemChanged( const QString& system )
460 {
461   QDS_Datum::unitSystemChanged( system );
462
463   Handle(TColStd_HArray1OfInteger) anIds;
464   Handle(TColStd_HArray1OfExtendedString) aValues, anIcons;
465
466   Handle(DDS_DicItem) aDicItem = dicItem();
467   if ( !aDicItem.IsNull() )
468     aDicItem->GetListOfValues( aValues, anIds, anIcons );
469
470   myValue.clear();
471   myIcons.clear();
472   myDataIds.clear();
473
474   QMap<int, QString> userMap;
475   QIntList::iterator iIt = myUserIds.begin();
476   QStringList::iterator sIt = myUserNames.begin();
477   for ( ; iIt != myUserIds.end() && sIt != myUserNames.end(); ++iIt, ++sIt )
478     userMap.insert( *iIt, *sIt );
479
480   if ( !anIds.IsNull() && !aValues.IsNull() &&
481        anIds->Length() == aValues->Length() )
482   {
483     for ( int i = anIds->Lower(); i <= anIds->Upper(); i++ )
484     {
485       QString aValue;
486       QPixmap aPixmap;
487       int id = anIds->Value( i );
488       if ( userMap.contains( id  ) )
489         aValue = userMap[id];
490       else
491       {
492         aValue = toQString( aValues->Value( i ) );
493         if ( !anIcons.IsNull() && i <= anIcons->Upper() )
494         {
495           QString anIconId = toQString( anIcons->Value( i ) );
496           if ( anIconId != "" )
497             aPixmap = QPixmap( anIconId );
498         }
499       }
500
501       myDataIds.append( id );
502       myValue.insert( id, aValue );
503       myState.insert( id, true );
504       if ( !aPixmap.isNull() )
505         myIcons.insert( id, aPixmap );
506     }
507   }
508
509   for ( iIt = myUserIds.begin(); iIt != myUserIds.end(); ++iIt )
510   {
511     int id = *iIt;
512     if ( !myValue.contains( id  ) )
513     {
514       myDataIds.append( id );
515       myValue.insert( id, userMap[id] );
516     }
517   }
518
519   QIntList del, add;
520   for ( IdStateMap::Iterator it1 = myState.begin(); it1 != myState.end(); ++it1 )
521     if ( !myValue.contains( it1.key() ) )
522       del.append( it1.key() );
523
524   for ( IdValueMap::Iterator it2 = myValue.begin(); it2 != myValue.end(); ++it2 )
525     if ( !myState.contains( it2.key() ) )
526       add.append( it2.key() );
527
528   for ( QIntList::iterator iter1 = del.begin(); iter1 != del.end(); ++iter1 )
529     myState.remove( *iter1 );
530
531   for ( QIntList::iterator iter2 = add.begin(); iter2 != add.end(); ++iter2 )
532     myState.insert( *iter2, true );
533
534   updateComboBox();
535 }
536
537 /*!
538   \brief Called when text in the combo box (editable) is modified by the user.
539   \param txt current text in the combo box editor (not used)
540 */
541 void QDS_ComboBox::onTextChanged( const QString& /*txt*/ )
542 {
543   onParamChanged();
544   emit paramChanged();
545   QString str = getString();
546   emit paramChanged( str );
547 }
548
549 /*!
550   \brief Called when combo box item is activated.
551   \param idx index of teh item being activated
552 */
553 void QDS_ComboBox::onActivated( int idx )
554 {
555   if ( comboBox() )
556     comboBox()->setCurrentIndex( comboBox()->currentIndex() );
557
558   int id = getId( idx );
559   if ( id != -1 )
560   {
561     onParamChanged();
562     QString str = getString();
563     emit activated( id );
564     emit activated( str );
565     emit paramChanged();
566     emit paramChanged( str );
567   }
568 }
569
570 /*!
571   \brief Update combo box.
572 */
573 void QDS_ComboBox::updateComboBox()
574 {
575   QtxComboBox* cb = comboBox();
576
577   int curId = -1;
578
579   bool isClear = false;
580
581   if ( cb )
582   {
583     isClear = cb->isCleared();
584
585     curId = getId( cb->currentIndex() );
586     cb->clear();
587   }
588
589   myIndex.clear();
590
591   int idx = 0;
592   for ( QIntList::const_iterator it = myDataIds.begin(); it != myDataIds.end(); ++it )
593   {
594     int id = *it;
595     if ( !myValue.contains( id ) || !myState.contains( id ) || !myState[id] )
596       continue;
597
598     myIndex.insert( id, idx++ );
599     if ( cb )
600     {
601       if ( myIcons.contains( id ) )
602         cb->addItem( QIcon(myIcons[id]), myValue[id] );
603       else
604         cb->addItem( myValue[id] );
605     }
606   }
607
608   if ( cb && cb->count() )
609   {
610     cb->setFont( cb->font() );
611     cb->updateGeometry();
612
613     if ( isClear )
614       cb->setItemText( cb->currentIndex(), "" );
615     else
616     {
617       if ( getIndex( curId ) != -1 )
618         cb->setCurrentIndex( getIndex( curId ) );
619       if ( curId != getId( cb->currentIndex() ) )
620         onActivated( cb->currentIndex() );
621     }
622   }
623 }
624
625 /*!
626   \brief Get index of the combo box item according to its identifier.
627   \param id item ID
628   \return item index or -1 if not found
629 */
630 int QDS_ComboBox::getIndex( const int id ) const
631 {
632   int idx = -1;
633   if ( myIndex.contains( id ) )
634     idx = myIndex[id];
635   return idx;
636 }
637
638 /*!
639   \brief Get index of the combo box item.
640   \param str combo box item
641   \return item index or -1 if not found
642 */
643 int QDS_ComboBox::getIndex( const QString& str ) const
644 {
645   int idx = -1;
646   QComboBox* cb = comboBox();
647   if ( cb )
648   {
649     for ( int i = 0; i < cb->count() && idx == -1; i++ )
650       if ( cb->itemText( i ) == str )
651         idx = i;
652   }
653   return idx;
654 }
655
656 /*!
657   \brief Get item identifier according to the specified index.
658   \param idx item index
659   \return item ID or -1 if index is out of range
660 */
661 int QDS_ComboBox::getId( const int idx ) const
662 {
663   int id = -1;
664   IdIndexMap::ConstIterator it = myIndex.begin();
665   for (; it != myIndex.end() && id == -1; ++it )
666     if ( it.value() == idx )
667       id = it.key();
668   return id;
669 }
670
671 /*!
672   \brief Get item identifier.
673   \param str combo box item
674   \return item ID or -1 if not found
675 */
676 int QDS_ComboBox::getId( const QString& str ) const
677 {
678   int id = -1;
679   int candidate = -1;
680   IdValueMap::ConstIterator it = myValue.begin();
681   for (; it != myValue.end() && id == -1; ++it )
682   {
683     if ( it.value() == str )
684     {
685       if ( state( it.key() ) )
686         id = it.key();
687       else
688         candidate = it.key();
689     }
690   }
691   if ( id == -1 )
692     id = candidate;
693
694   return id;
695 }
696
697 /*!
698   \fn void QDS_ComboBox::activated( int id );
699   \brief Emitted when the current item in the combo box is changed.
700   \param id current item ID
701 */
702
703 /*!
704   \fn void QDS_ComboBox::activated( const QString& txt );
705   \brief Emitted when the current item in the combo box is changed.
706   \param txt current item text
707 */