Salome HOME
Merge remote branch 'origin/V7_dev'
[modules/gui.git] / src / SalomeApp / SalomeApp_ListView.cxx
1 // Copyright (C) 2007-2016  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, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // File   : SalomeApp_ListView.cxx
24 // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
25 //
26 #include "SalomeApp_ListView.h"
27 #include "SalomeApp_Application.h"
28
29 #include "SUIT_ResourceMgr.h"
30 #include "SUIT_Session.h"
31
32 #include "utilities.h"
33
34 #include <QValidator>
35 #include <QToolButton>
36 #include <QPixmap>
37 #include <QHeaderView>
38 #include <QKeyEvent>
39
40 #include <TColStd_ListOfInteger.hxx>
41 #include <TColStd_ListOfReal.hxx>
42
43 #include <TColStd_ListIteratorOfListOfInteger.hxx>
44 #include <TColStd_ListIteratorOfListOfReal.hxx>
45
46 /*!
47   Used for resizing editing widget
48 */
49 void computeEditGeometry(SalomeApp_ListViewItem* theItem,
50                          SalomeApp_EntityEdit*   theWidget)
51 {
52   if (!theItem)
53     return;
54   QTreeWidget* aListView = theItem->treeWidget();
55   int anEditColumn = theItem->getEditedColumn();
56   if (anEditColumn < 0)
57     return;
58
59   int aX = 0, aY = 0, aW = 0, aH = 0;
60
61   QRect aRect = aListView->visualItemRect(theItem);
62   aX = aListView->header()->sectionViewportPosition(anEditColumn);
63   if (aX < 0)
64     aX = 0; // THIS CAN BE REMOVED
65   QSize aSize = theWidget->getControl()->sizeHint();
66   aH = qMax(aSize.height() , aRect.height() );
67   aY = aRect.y() - ((aH - aRect.height()) / 2);
68   //aW = aListView->columnWidth(anEditColumn); // CAN SUBSTITUTE NEXT 3 ROWS
69   aW = aListView->viewport()->width() - aX;
70   if (aW < 0)
71     aW = 0;
72   theWidget->setGeometry(aX, aY, aW, aH);
73 }
74
75 /*!
76   Constructor
77 */
78 SalomeApp_ListView::SalomeApp_ListView( QWidget* parent )
79   : QTreeWidget/*QtxListView*/( parent )
80 {
81   myMouseEnabled = true;
82   myEditingEnabled = false;
83   setSelectionMode(QAbstractItemView::SingleSelection);
84   setRootIsDecorated(false);
85   setAllColumnsShowFocus(false);
86 //  header()->setClickEnabled(false);
87 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
88   header()->setMovable(false);
89 #else
90   header()->setSectionsMovable(false);
91 #endif
92
93   myEditedItem = 0;
94   myEdit = 0;
95
96   viewport()->installEventFilter(this);
97
98   connect(this, SIGNAL(itemSelectionChanged()),
99           this, SLOT(onSelectionChanged()));
100   connect(header(), SIGNAL(sizeChange(int, int, int)),
101           this,     SLOT(onHeaderSizeChange(int, int, int)));
102 }
103
104 /*!
105   Destructor
106 */
107 SalomeApp_ListView::~SalomeApp_ListView()
108 {
109   if (myEdit) {
110     delete myEdit;
111   }
112   myEdit = 0;
113   myEditedItem = 0;
114 }
115
116 /*!
117   Updates all data viewer
118 */
119 void SalomeApp_ListView::updateViewer()
120 {
121   // temporary disconnecting selection changed SIGNAL
122   blockSignals(true);
123   QTreeWidgetItemIterator it( this );
124   SalomeApp_ListViewItem* aRoot = (SalomeApp_ListViewItem*)(*it);
125   if (aRoot)
126     aRoot->updateAllLevels();
127   update( contentsRect() );//updateContents();
128   // connecting again selection changed SIGNAL
129   blockSignals(false);
130   emit itemSelectionChanged();
131 }
132
133 /*!
134   Updates currently selected item(s)
135 */
136 void SalomeApp_ListView::updateSelected()
137 {
138   // temporary disconnecting selection changed SIGNAL
139   blockSignals(true);
140   SalomeApp_ListViewItem* aChild = (SalomeApp_ListViewItem*)(selectedItems().first());
141   if (aChild)
142     aChild->updateAllLevels();
143   update( contentsRect() );//updateContents();
144   // connecting again selection changed SIGNAL
145   blockSignals(false);
146   emit itemSelectionChanged();
147 }
148
149 /*!
150   Returns popup client type
151 */
152 QString SalomeApp_ListView::popupClientType() const
153 {
154   return "SalomeApp_ListView";
155 }
156
157 /*!
158   Fills popup menu with items
159 */
160 void SalomeApp_ListView::contextMenuPopup( QMenu* aPopup )
161 {
162   if (aPopup) {
163     // add items here...
164   }
165 }
166
167 /*!
168   Clears view
169 */
170 void SalomeApp_ListView::clear()
171 {
172   if (myEdit) {
173     delete myEdit;
174     myEdit = 0;
175     myEditedItem = 0;
176   }
177   QTreeWidget::clear();
178 }
179
180 /*!
181   \return true if mouse events are enabled
182 */
183 bool SalomeApp_ListView::isMouseEnabled()
184 {
185   return myMouseEnabled;
186 }
187
188 /*!
189   Enables/disables mouse events (excluding MouseMove)
190 */
191 void SalomeApp_ListView::enableMouse(bool enable)
192 {
193   myMouseEnabled = enable;
194 }
195
196 /*!
197   Event filter
198 */
199 bool SalomeApp_ListView::eventFilter(QObject* object, QEvent* event)
200 {
201   if (object == viewport() &&
202        (event->type() == QEvent::MouseButtonPress   ||
203         event->type() == QEvent::MouseButtonRelease ||
204         event->type() == QEvent::MouseButtonDblClick)  &&
205       !isMouseEnabled())
206     return true;
207   else
208     return QTreeWidget::eventFilter(object, event);
209 }
210
211 /*!
212   Setting editing of items availbale/not available
213 */
214 void SalomeApp_ListView::enableEditing(bool theFlag)
215 {
216   myEditingEnabled = theFlag;
217   if (!myEditingEnabled) {
218     if (myEdit) {
219       delete myEdit;
220       myEdit = 0;
221       myEditedItem = 0;
222     }
223   }
224 }
225
226 /*!
227   Says if editing is enabled
228 */
229 bool SalomeApp_ListView::isEnableEditing()
230 {
231   return myEditingEnabled;
232 }
233
234 /*!
235   Calls finishEditing(true)...
236 */
237 void SalomeApp_ListView::accept()
238 {
239   finishEditing(true);
240 }
241
242 /*!
243   Slot, called when selection changed in List Viewer
244 */
245 void SalomeApp_ListView::onSelectionChanged()
246 {
247   if (myEdit) {
248     finishEditing(true);
249     delete myEdit;
250     myEdit = 0;
251     if (myEditedItem && !myEditedItem->isAccepted()) {
252       delete myEditedItem;
253       update( contentsRect() );//updateContents();
254     }
255     myEditedItem = 0;
256   }
257   // editing is allowed in Single Selection Mode only
258   if (selectionMode() != QAbstractItemView::SingleSelection || !isEnableEditing())
259     return;
260   SalomeApp_ListViewItem* anItem = (SalomeApp_ListViewItem*)(selectedItems().first());
261   if (anItem) {
262     if (!anItem->isEditable())
263       return;
264     myEdit = anItem->startEditing();
265     if (myEdit) {
266       connect(myEdit, SIGNAL(returnPressed()), this, SLOT(onEditOk()));
267       connect(myEdit, SIGNAL(escapePressed()), this, SLOT(onEditCancel()));
268       myEditedItem = anItem;
269       myEdit->show();
270       myEdit->setFocus();
271     }
272   }
273 }
274
275 /*!
276   Called when Data Viewer is resized
277 */
278 void SalomeApp_ListView::resizeEvent( QResizeEvent * e)
279 {
280   QTreeWidget::resizeEvent(e);
281   int aW = columnWidth(columnCount()-1);
282   int aX = header()->sectionPosition(columnCount()-1);
283   if (aW < width() - frameWidth() * 2 - aX - 1)
284     setColumnWidth(columnCount()-1, width() - frameWidth() * 2 - aX - 1);
285   update( contentsRect() );//updateContents();
286 }
287
288 /*!
289   Slot, called when columns sizes are changed
290 */
291 void SalomeApp_ListView::onHeaderSizeChange(int, int, int)
292 {
293   int aW = columnWidth(columnCount()-1);
294   int aX = header()->sectionPosition(columnCount()-1);
295   if (aW < width() - frameWidth() * 2 - aX - 1)
296     setColumnWidth(columnCount()-1, width() - frameWidth() * 2 - aX - 1);
297 }
298
299 /*!
300   Handler for paint event
301 */
302 void SalomeApp_ListView::viewportPaintEvent(QPaintEvent* e)
303 {
304   QTreeWidget::paintEvent(e);
305   if (myEditedItem && myEdit) {
306     computeEditGeometry(myEditedItem, myEdit);
307   }
308 }
309
310 /*!
311   Called when user finishes in editing of item
312 */
313 void SalomeApp_ListView::onEditOk()
314 {
315   finishEditing(true);
316 }
317
318 /*!
319   Called when user cancels item editing
320 */
321 void SalomeApp_ListView::onEditCancel()
322 {
323   finishEditing(false);
324 }
325
326 /*!
327   Finishes editing of entity
328 */
329 UpdateType SalomeApp_ListView::finishEditing(bool ok)
330 {
331   UpdateType aNeedsUpdate = utCancel;
332   if (myEditedItem && myEdit)
333   {
334     disconnect(myEdit, SIGNAL(returnPressed()), this, SLOT(onEditOk()));
335     disconnect(myEdit, SIGNAL(escapePressed()), this, SLOT(onEditCancel()));
336     myEditedItem->setAccepted(true);
337     if (ok) {
338       aNeedsUpdate = myEditedItem->finishEditing(myEdit);
339       if (aNeedsUpdate == utCancel) {
340         // something to do here on Cancel...
341       }
342       else {
343         // something to do here on OK...
344       }
345       // updating contents
346       switch (aNeedsUpdate) {
347       case utUpdateItem:
348         {
349           if (myEditedItem)
350             myEditedItem->updateAllLevels();
351           break;
352         }
353       case utUpdateParent:
354         {
355           if (myEditedItem) {
356             SalomeApp_ListViewItem* aParent = (SalomeApp_ListViewItem*)(myEditedItem->parent());
357             if (aParent)
358               aParent->updateAllLevels();
359             else
360               myEditedItem->updateAllLevels();
361           }
362           break;
363         }
364       case utUpdateViewer:
365         {
366           updateViewer();
367           break;
368         }
369       case utUpdateAll:
370         {
371           // doing the same as for utUpdateViewer here
372           // descendants can add extra processing
373           updateViewer();
374           break;
375         }
376       default:
377         break;
378       }
379     }
380   }
381
382   // hide <myEdit> widget
383   if (myEdit) {
384     myEdit->hide();
385   }
386
387   return aNeedsUpdate;
388 }
389
390 /*!
391   \return current tooltip for list view
392   \retval valid rect in success
393 */
394 QRect SalomeApp_ListView::tip(QPoint aPos,
395                               QString& aText,
396                               QRect& dspRect,
397                               QFont& dspFnt) const
398 {
399   QRect result( -1, -1, -1, -1 );
400   SalomeApp_ListViewItem* aItem = (SalomeApp_ListViewItem*)itemAt( aPos );
401   if ( aItem ) {
402     for (int i = 0; i < columnCount(); i++) {
403       QRect aItemRect = aItem->itemRect(i);
404       QRect aTextRect = aItem->textRect(i);
405       if ( !aItem->text(i).isEmpty() &&
406            ( aItemRect.width()  > header()->sectionSize(i) ||
407              aTextRect.left()   < 0 ||
408              aTextRect.top()    < 0 ||
409              aTextRect.right()  > viewport()->width() ||
410              aTextRect.bottom() > viewport()->height() ) ) {
411         // calculating tip data
412         aText   = aItem->tipText();
413         dspRect = aItem->tipRect();
414         dspFnt  = font();
415         if (dspRect.isValid()) {
416           result  = QRect(QPoint(0, aItemRect.top()),
417                           QSize(viewport()->width(), aItemRect.height()));
418         }
419       }
420     }
421   }
422   return result;
423 }
424
425 /*!
426   Constructor
427 */
428 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListView* parent) :
429 QTreeWidgetItem( parent )
430 {
431   init();
432 }
433
434 /*!
435   Constructor
436 */
437 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListView*     parent,
438                                                SalomeApp_ListViewItem* after) :
439 QTreeWidgetItem( parent, after )
440 {
441   init();
442 }
443
444 /*!
445   Constructor
446 */
447 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListView*     parent,
448                                                const QStringList&    theStrings,
449                                                const bool        theEditable) :
450 QTreeWidgetItem(parent, theStrings)
451 {
452   init();
453   setEditable(theEditable);
454 }
455
456 /*!
457   Constructor
458 */
459 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListViewItem* parent,
460                                                const QStringList&    theString,
461                                                const bool        theEditable) :
462 QTreeWidgetItem(parent, theString)
463 {
464   init();
465   setEditable(theEditable);
466 }
467
468 /*!
469   Constructor
470 */
471 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListViewItem* parent,
472                                                SalomeApp_ListViewItem* after,
473                                                const QString&    theName,
474                                                const bool        theEditable) :
475 QTreeWidgetItem(parent, after)
476 {
477   setData(0,Qt::DisplayRole,QVariant(theName));
478   init();
479   setEditable(theEditable);
480 }
481
482 /*!
483   Constructor
484 */
485 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListView*     parent,
486                                                SalomeApp_ListViewItem* after,
487                                                const QString&    theName,
488                                                const bool        theEditable) :
489 QTreeWidgetItem(parent, after)
490 {
491   setData(0,Qt::DisplayRole,QVariant(theName));
492   init();
493   setEditable(theEditable);
494 }
495
496 /*!
497   Constructor
498 */
499 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListViewItem* parent,
500                                                SalomeApp_ListViewItem* after,
501                                                const QString&    theName,
502                                                const QString&    theValue,
503                                                const bool        theEditable) :
504 QTreeWidgetItem(parent, after)
505 {
506   setData(0,Qt::DisplayRole,QVariant(theName));
507   setData(1,Qt::DisplayRole,QVariant(theValue));
508   init();
509   setEditable(theEditable);
510 }
511
512 /*!
513   Constructor
514 */
515 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListView*     parent,
516                                                SalomeApp_ListViewItem* after,
517                                                const QString&    theName,
518                                                const QString&    theValue,
519                                                const bool        theEditable) :
520 QTreeWidgetItem(parent, after)
521 {
522   setData(0,Qt::DisplayRole,QVariant(theName));
523   setData(1,Qt::DisplayRole,QVariant(theValue));
524   init();
525   setEditable(theEditable);
526 }
527
528 /*!
529   Destructor
530 */
531 SalomeApp_ListViewItem::~SalomeApp_ListViewItem()
532 {
533 }
534
535 /*!
536   Initialization
537 */
538 void SalomeApp_ListViewItem::init()
539 {
540   myEditable    = false;
541   myAccepted    = true;
542   myEditingType = (int)SalomeApp_EntityEdit::etLineEdit;
543   myValueType   = (int)SalomeApp_EntityEdit::vtString;
544   myButtons     = 0;
545   myUserType    = -1;
546 }
547
548 /*!
549   Returns the depth of this item
550 */
551 int SalomeApp_ListViewItem::depth() const
552 {
553   int aDepth = 0;
554   QTreeWidgetItem* aParent = parent();
555   while ( aParent ) {
556     aParent = aParent->parent();
557     aDepth++;
558   }
559   return aDepth;
560 }
561
562 /*!
563   \return text in the first column
564 */
565 QString SalomeApp_ListViewItem::getName() const
566 {
567   return ( treeWidget()->columnCount() > 0 ) ? text(0) : QString("");
568 }
569
570 /*!
571   Sets text in the first column
572 */
573 UpdateType SalomeApp_ListViewItem::setName(const QString& theName)
574 {
575   UpdateType aNeedsUpdate = utCancel;
576   if (treeWidget()->columnCount() > 0) {
577     setText(0, theName);
578     aNeedsUpdate = utNone;
579   }
580   return aNeedsUpdate;
581 }
582
583 /*!
584   \return text in the second column
585 */
586 QString SalomeApp_ListViewItem::getValue() const
587 {
588   return ( treeWidget()->columnCount() > 1 ) ? text(1) : QString("");
589 }
590
591 /*!
592   Sets text in the second column
593 */
594 UpdateType SalomeApp_ListViewItem::setValue(const QString& theValue)
595 {
596   UpdateType aNeedsUpdate = utCancel;
597   if (treeWidget()->columnCount() > 1) {
598     setText(1, theValue);
599     aNeedsUpdate = utNone;
600   }
601   return aNeedsUpdate;
602 }
603
604 /*!
605   \return full path to the entity from the root
606 */
607 QString SalomeApp_ListViewItem::fullName()
608 {
609   QString aFullName = getName();
610   SalomeApp_ListViewItem* aParent = (SalomeApp_ListViewItem*)parent();
611   while(aParent != NULL) {
612     aFullName = aParent->getName() + QString(".") + aFullName;
613     aParent = (SalomeApp_ListViewItem*)(aParent->parent());
614   }
615   return aFullName;
616 }
617
618 /*!
619   expands all entities beginning from this level
620 */
621 void SalomeApp_ListViewItem::openAllLevels()
622 {
623   setExpanded(true);
624   QTreeWidgetItemIterator it( this );
625   SalomeApp_ListViewItem* aChild = (SalomeApp_ListViewItem*)(*it);
626   while( aChild ) {
627     aChild->openAllLevels();
628     ++it;
629     aChild = (SalomeApp_ListViewItem*)(*it);
630   }
631 }
632
633 /*!
634   update all entites beginning from this level
635 */
636 void SalomeApp_ListViewItem::updateAllLevels()
637 {
638   QTreeWidgetItemIterator it( this );
639   SalomeApp_ListViewItem* aChild = (SalomeApp_ListViewItem*)(*it);
640   while( aChild ) {
641     aChild->updateAllLevels();
642     ++it;
643     aChild = (SalomeApp_ListViewItem*)(*it);
644   }
645 }
646
647 /*!
648   \return true if entity is editable
649 */
650 bool SalomeApp_ListViewItem::isEditable() const
651 {
652   return myEditable;
653 }
654
655 /*!
656   Sets editable flag fo the entity
657 */
658 void SalomeApp_ListViewItem::setEditable(bool theEditable)
659 {
660   myEditable = theEditable;
661 }
662
663 /*!
664   \return true if entitiy is accepted after editing
665 */
666 bool SalomeApp_ListViewItem::isAccepted() const
667 {
668   return myAccepted;
669 }
670
671 /*!
672   Sets entitiy accepted or not after editing
673 */
674 void SalomeApp_ListViewItem::setAccepted(bool theAccepted)
675 {
676   myAccepted = theAccepted;
677 }
678
679 /*!
680  \retval type of edit control (default is edit box)
681       \li 0 - edit box
682       \li 1 - combo box
683       \li 2 - editable combo box
684 */
685 int SalomeApp_ListViewItem::getEditingType()
686 {
687   return myEditingType;
688 }
689
690 /*!
691  \retval type of edit control (negative value means none)
692      \li 0 - edit box
693      \li 1 - combo box
694      \li 2 - editable combo box
695 */
696 void SalomeApp_ListViewItem::setEditingType(const int type)
697 {
698   myEditingType = type;
699 }
700
701 /*! \retval edited column, default is last column
702     negative value means there are no editable columns
703 */
704 int SalomeApp_ListViewItem::getEditedColumn()
705 {
706   return treeWidget()->columnCount()-1;
707 }
708
709 /*!
710   \retval type of edited value (string, int, double)
711    default is string
712 */
713 int SalomeApp_ListViewItem::getValueType()
714 {
715   return myValueType;
716 }
717
718 /*!
719   Sets type of edited value
720 */
721 void SalomeApp_ListViewItem::setValueType(const int valueType)
722 {
723   myValueType = valueType;
724 }
725
726 /*!
727   Sets type of edited value
728 */
729 int SalomeApp_ListViewItem::getUserType()
730 {
731   return myUserType;
732 }
733
734 /*!
735   Sets type of edited value
736 */
737 void SalomeApp_ListViewItem::setUserType(const int userType)
738 {
739   myUserType = userType;
740 }
741
742 /*!
743   \return buttons for editing widget (Apply (V), Cancel (X))
744    default is both buttons
745 */
746 int SalomeApp_ListViewItem::getButtons()
747 {
748   return myButtons;
749 }
750
751 /*!
752   Sets buttons for editing widget (Apply (V), Cancel (X))
753 */
754 void SalomeApp_ListViewItem::setButtons(const int buttons)
755 {
756   myButtons = buttons;
757 }
758
759 /*!
760   Creates control for editing and fills it with values
761 */
762 SalomeApp_EntityEdit* SalomeApp_ListViewItem::startEditing()
763 {
764   SalomeApp_EntityEdit* aWidget = 0;
765   QTreeWidget* aListView = treeWidget();
766   if (aListView) {
767     if (!isEditable())
768       return 0;
769     int anEditType   = getEditingType();
770     int aValueType   = getValueType();
771     int aButtons     = getButtons();
772     int anEditColumn = getEditedColumn();
773     if (anEditColumn < 0 || anEditType < 0)
774       return 0;
775     aWidget = new SalomeApp_EntityEdit(aListView->viewport(),
776                                  anEditType,
777                                  aValueType,
778                                  aButtons & SalomeApp_EntityEdit::btApply,
779                                  aButtons & SalomeApp_EntityEdit::btCancel);
780     computeEditGeometry(this, aWidget);
781
782     fillWidgetWithValues(aWidget);
783   }
784   return aWidget;
785 }
786
787 /*!
788   Fills widget with initial values (list or single value)
789 */
790 void SalomeApp_ListViewItem::fillWidgetWithValues(SalomeApp_EntityEdit* theWidget)
791 {
792   int anEditColumn = getEditedColumn();
793   if (theWidget && anEditColumn >= 0 && !text(anEditColumn).isEmpty())
794     theWidget->insertItem(text(anEditColumn), true);
795 }
796
797 /*!
798   Finishes editing of entity
799 */
800 UpdateType SalomeApp_ListViewItem::finishEditing(SalomeApp_EntityEdit* theWidget)
801 {
802   UpdateType aNeedsUpdate = utCancel;
803   try {
804     if (theWidget) {
805       int anEditColumn = getEditedColumn();
806       switch (anEditColumn) {
807       case 0:
808         aNeedsUpdate = setName(theWidget->getText());
809         break;
810       case 1:
811         aNeedsUpdate = setValue(theWidget->getText());
812         break;
813       default:
814         break;
815       }
816     }
817   }
818   catch (...) {
819     MESSAGE( "System error has been caught - SalomeApp_ListViewItem::finishEditing" )
820   }
821   return aNeedsUpdate;
822 }
823
824 /*!
825   Calculates rectangle which should contain item's tip
826 */
827 QRect SalomeApp_ListViewItem::tipRect()
828 {
829   QRect aRect = QRect(-1, -1, -1, -1);
830   QRect aItemRect = treeWidget()->visualItemRect(this);
831   if ( !aItemRect.isValid() )
832     return aItemRect;
833
834   QString aTip = tipText();
835   if (!aTip.isEmpty()) {
836     QRect aRect0 = textRect(0);
837     QFont aFont(treeWidget()->font());
838     QFontMetrics fm(aFont);
839     int iw = fm.width(aTip);
840     aRect = QRect(QPoint(aRect0.x() < 0 ? 0 : aRect0.x(),
841                          aRect0.y()),
842                   QSize (iw,
843                          aRect0.height()));
844   }
845   return aRect;
846 }
847
848 /*!
849   \return text for tooltip
850 */
851 QString SalomeApp_ListViewItem::tipText()
852 {
853   QString aText = getName();
854   if (!getValue().isEmpty())
855     aText += QString(" : ") + getValue();
856   return aText;
857 }
858
859 /*!
860   Calculates rect of item text in viewport coordinates
861 */
862 QRect SalomeApp_ListViewItem::textRect(const int column) const
863 {
864   QRect aItemRect = treeWidget()->visualItemRect( this );
865   if ( !aItemRect.isValid() )
866     return aItemRect;
867
868   QFont aFont(treeWidget()->font());
869   QFontMetrics fm(aFont);
870
871   int decorWidth  = ( treeWidget()->rootIsDecorated() ) ?
872                     ( treeWidget()->indentation() * (depth() + 1) ) :
873                     ( treeWidget()->indentation() *  depth() );
874   int pixmapWidth = ( !icon(column).isNull() ) ?
875                       treeWidget()->iconSize().width() + 2 :
876                       1;
877   int prevWidth = 0;
878   for (int i = 0; i < column; i++)
879     prevWidth += treeWidget()->header()->sectionSize(i);
880   int ix = prevWidth   +
881            pixmapWidth +
882            ((column == 0) ? decorWidth : 0);
883   int iy = aItemRect.y();
884   int iw = fm.width(text(column));
885   int ih = aItemRect.height();
886   if (!icon(column).isNull()) {
887     iy += 1;
888     ih -= 2;
889   }
890   ix -= treeWidget()->contentsRect().left();
891
892   QRect theResult(QPoint(ix, iy), QSize(iw, ih));
893   return theResult;
894 }
895
896 /*!
897   Calculates rect of item data in viewport coordinates
898 */
899 QRect SalomeApp_ListViewItem::itemRect(const int column) const
900 {
901   QRect aItemRect = treeWidget()->visualItemRect( this );
902   if ( !aItemRect.isValid() )
903     return aItemRect;
904
905   QFont aFont(treeWidget()->font());
906   QFontMetrics fm(aFont);
907
908   int decorWidth  = ( treeWidget()->rootIsDecorated() ) ?
909                     ( treeWidget()->indentation() * (depth() + 1) ) :
910                     ( treeWidget()->indentation() *  depth() );
911   int pixmapWidth = ( !icon(column).isNull() ) ?
912                       treeWidget()->iconSize().width() + 2 :
913                       0;
914   int prevWidth = 0;
915   for (int i = 0; i < column; i++)
916     prevWidth += treeWidget()->header()->sectionSize(i);
917   int ix = prevWidth;
918   int iy = aItemRect.y();
919   int iw = pixmapWidth +
920            2 +
921            ((column == 0) ? decorWidth : 0) +
922            fm.width(text(column));
923   int ih = aItemRect.height();
924   ix -= treeWidget()->contentsRect().left();
925
926   QRect theResult(QPoint(ix, iy), QSize(iw, ih));
927   return theResult;
928 }
929
930 /*!
931   Constructor
932 */
933 SalomeApp_EditBox::SalomeApp_EditBox(QWidget* parent) :
934 QLineEdit(parent)
935 {
936 }
937
938 /*!
939   Event filter for key pressing
940 */
941 void SalomeApp_EditBox::keyPressEvent( QKeyEvent *e )
942 {
943   if ( e->key() == Qt::Key_Escape )
944     emit escapePressed();
945   else
946     QLineEdit::keyPressEvent( e );
947   e->accept();
948 }
949
950
951 /*!
952   Constructor
953 */
954 SalomeApp_ComboBox::SalomeApp_ComboBox(bool rw, QWidget* parent, const char* name) :
955 QComboBox(parent)
956 {
957   setEditable( rw );
958   setObjectName( name );
959 }
960
961 /*!
962   Searches item in list and returns its index
963 */
964 int SalomeApp_ComboBox::findItem(const QString& theText)
965 {
966   for (int i = 0; i < count(); i++)
967     if (itemText(i) == theText)
968       return i;
969   return -1;
970 }
971
972 /*!
973   Adds item in combo box
974 */
975 void SalomeApp_ComboBox::insertItem(const QString& theValue,
976                                     int            theIndex)
977 {
978   if (duplicatesEnabled() || findItem(theValue) < 0)
979     QComboBox::insertItem(theIndex, theValue);
980 }
981
982 /*!
983   Adds list of items in combo box
984 */
985 void SalomeApp_ComboBox::insertList(const QStringList& theList)
986 {
987   for (unsigned i = 0; i < theList.count(); i++)
988     insertItem(theList[i]);
989 }
990
991 /*!
992   Adds item in combo box
993 */
994 void SalomeApp_ComboBox::insertItem(const int theValue)
995 {
996   int aNum;
997   bool bOk;
998   for (int i = 0; i < count(); i++) {
999     aNum = itemText(i).toInt(&bOk);
1000     if (bOk) {
1001       if (aNum > theValue || (aNum == theValue && duplicatesEnabled())) {
1002         insertItem(QString::number(theValue),i);
1003         return;
1004       }
1005     }
1006   }
1007   insertItem(QString::number(theValue));
1008 }
1009
1010 /*!
1011   Adds list of items in combo box
1012 */
1013 void SalomeApp_ComboBox::insertList(const TColStd_ListOfInteger& theList)
1014 {
1015   for (TColStd_ListIteratorOfListOfInteger aIter(theList); aIter.More(); aIter.Next())
1016     insertItem(aIter.Value());
1017 }
1018
1019 /*!
1020   Adds item in combo box
1021 */
1022 void SalomeApp_ComboBox::insertItem(const double theValue)
1023 {
1024   double aNum;
1025   bool bOk;
1026   for (int i = 0; i < count(); i++) {
1027     aNum = itemText(i).toDouble(&bOk);
1028     if (bOk) {
1029       if (aNum > theValue || (aNum == theValue && duplicatesEnabled())) {
1030         insertItem(QString::number(theValue), i);
1031         return;
1032       }
1033     }
1034   }
1035   insertItem(QString::number(theValue));
1036 }
1037
1038 /*!
1039   Adds list of items in combo box
1040 */
1041 void SalomeApp_ComboBox::insertList(const TColStd_ListOfReal& theList)
1042 {
1043   for (TColStd_ListIteratorOfListOfReal aIter(theList); aIter.More(); aIter.Next())
1044     insertItem(aIter.Value());
1045 }
1046
1047 #include <qlayout.h>
1048
1049 #define MIN_COMBO_WIDTH     1
1050 #define MIN_EDIT_WIDTH      1
1051
1052 /*!
1053   Constructor
1054 */
1055 SalomeApp_EntityEdit::SalomeApp_EntityEdit(QWidget* parent,
1056                                int      controlType,
1057                                int      valueType,
1058                                bool     butApply,
1059                                bool     butCancel) :
1060 QWidget(parent),
1061 myEdit(0),
1062 myCombo(0),
1063 myApplyBtn(0),
1064 myCancelBtn(0)
1065 {
1066   SalomeApp_Application* app = dynamic_cast<SalomeApp_Application*>( SUIT_Session::session()->activeApplication() );
1067   SUIT_ResourceMgr* mgr = app ? app->resourceMgr() : NULL;
1068
1069   QHBoxLayout* aTopLayout = new QHBoxLayout(this);
1070   aTopLayout->setAlignment( Qt::AlignTop );
1071   aTopLayout->setSpacing( 0 );
1072   aTopLayout->setMargin( 1 );
1073   if (controlType != etLineEdit &&
1074       controlType != etComboBox &&
1075       controlType != etComboEdit)
1076     controlType = etLineEdit;
1077   if (controlType == etComboBox || controlType == etComboEdit) {
1078     // this is an editable combo box
1079     myCombo = new SalomeApp_ComboBox(controlType == etComboEdit, this);
1080     myCombo->setMinimumSize(MIN_COMBO_WIDTH, 0);
1081     myCombo->setSizePolicy(QSizePolicy(QSizePolicy::Expanding,
1082                                        QSizePolicy::Fixed));
1083     // no insertions
1084     myCombo->setInsertPolicy(QComboBox::NoInsert);
1085     // no duplicates enabled by default
1086     myCombo->setDuplicatesEnabled(false);
1087     aTopLayout->addWidget(myCombo);
1088     // connect signals
1089     connect(myCombo, SIGNAL(activated(const QString&)), this, SLOT(onComboActivated(const QString&)));
1090     connect(myCombo, SIGNAL(textChanged(const QString&)), this, SLOT(onTextChanged(const QString&)));
1091   }
1092   else {
1093     // and this is an edit box
1094     myEdit = new SalomeApp_EditBox(this);
1095     myEdit->setMinimumSize(MIN_EDIT_WIDTH, 0);
1096     myEdit->setSizePolicy(QSizePolicy(QSizePolicy::Expanding,
1097                                       QSizePolicy::Fixed));
1098     aTopLayout->addWidget(myEdit);
1099     connect(myEdit, SIGNAL(textChanged(const QString&)), this, SLOT(onTextChanged(const QString&)));
1100     connect(myEdit, SIGNAL(returnPressed()), this, SLOT(onApply()));
1101     connect(myEdit, SIGNAL(escapePressed()), this, SLOT(onCancel()));
1102   }
1103   if (valueType != vtString &&
1104       valueType != vtInteger &&
1105       valueType != vtDouble)
1106     valueType = vtString;
1107   if (valueType == vtInteger)
1108     setValidator(new QIntValidator(this));
1109   else if (valueType == vtDouble)
1110     setValidator(new QDoubleValidator(this));
1111   if (butApply) {
1112     // Apply button (V)
1113     myApplyBtn = new QToolButton(this);
1114
1115     QPixmap anIcon;
1116     if( mgr )
1117       anIcon = mgr->loadPixmap( "SalomeApp", tr( "ICON_APPLY" ), false );
1118
1119     myApplyBtn->setIcon(anIcon);
1120     myApplyBtn->setEnabled(false);
1121     myApplyBtn->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
1122     myApplyBtn->setMinimumSize(16, 16);
1123     myApplyBtn->setMaximumSize(16, 20);
1124     aTopLayout->addWidget(myApplyBtn);
1125     connect(myApplyBtn, SIGNAL(clicked()), this, SLOT(onApply()));
1126   }
1127   if (butCancel) {
1128     // Cancel button (X)
1129     myCancelBtn = new QToolButton(this);
1130     QPixmap anIcon;
1131     if( mgr )
1132       anIcon = mgr->loadPixmap( "SalomeApp", tr( "ICON_CANCEL" ), false );
1133     myCancelBtn->setIcon(anIcon);
1134     myCancelBtn->setEnabled(false);
1135     myCancelBtn->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
1136     myCancelBtn->setMinimumSize(16, 16);
1137     myCancelBtn->setMaximumSize(16, 20);
1138     aTopLayout->addWidget(myCancelBtn);
1139     connect(myCancelBtn, SIGNAL(clicked()), this, SLOT(onCancel()));
1140   }
1141 }
1142
1143 /*!
1144   Destructor
1145 */
1146 SalomeApp_EntityEdit::~SalomeApp_EntityEdit()
1147 {
1148 }
1149
1150 /*!
1151   Clears edit/combo box
1152 */
1153 void SalomeApp_EntityEdit::clear()
1154 {
1155   if (myEdit)
1156     myEdit->clear();
1157   if (myCombo)
1158     myCombo->clear();
1159 }
1160
1161 /*!
1162   \return current text in edit box or combo box
1163 */
1164 QString SalomeApp_EntityEdit::getText()
1165 {
1166   if (myEdit)
1167     return myEdit->text();
1168   else if (myCombo)
1169     return myCombo->currentText();
1170   else
1171     return "";
1172 }
1173
1174 /*!
1175   Sets text
1176 */
1177 void SalomeApp_EntityEdit::setText(const QString& theText)
1178 {
1179   myString = theText;
1180   if (myEdit)
1181     myEdit->setText(theText);
1182   if (myCombo) {
1183     int aFound = myCombo->findItem(theText);
1184     if (aFound >= 0) {
1185       myCombo->setCurrentIndex(aFound);
1186       onTextChanged(theText);
1187     }
1188   }
1189 }
1190
1191 /*!
1192   Adds item in combo box, sets it current if theSetCurrent is true
1193 */
1194 void SalomeApp_EntityEdit::insertItem(const QString& theValue,
1195                                 bool           theSetCurrent,
1196                                 int            theOrder)
1197 {
1198   if (myCombo) {
1199     int aIndexAt = -1;
1200     if (theOrder == atTop)
1201       aIndexAt = 0;
1202     else if (theOrder == atBeforeCurrent && myCombo->count() > 0)
1203       aIndexAt = myCombo->currentIndex();
1204     else if (theOrder == atAfterCurrent &&
1205              myCombo->count() > 0 &&
1206              myCombo->currentIndex() < myCombo->count()-1)
1207       aIndexAt = myCombo->currentIndex() + 1;
1208     myCombo->insertItem(theValue, aIndexAt);
1209   }
1210   if (theSetCurrent)
1211     setText(theValue);
1212 }
1213
1214 /*!
1215   Adds items in combo box, sets item theCurrent as current
1216 */
1217 void SalomeApp_EntityEdit::insertList(const QStringList& theList,
1218                                 const int          theCurrent)
1219 {
1220   if (myCombo)
1221     myCombo->insertList(theList);
1222   if (theCurrent >= 0 && theCurrent < (int)theList.count())
1223     setText(theList[theCurrent]);
1224 }
1225
1226 /*!
1227   Adds item in combo box, sets it current if theSetCurrent is true
1228 */
1229 void SalomeApp_EntityEdit::insertItem(const int theValue,
1230                                 bool      theSetCurrent)
1231 {
1232   if (myCombo) {
1233     myCombo->insertItem(theValue);
1234   }
1235   if (theSetCurrent)
1236     setText(QString::number(theValue));
1237 }
1238
1239 /*!
1240   Adds items in combo box, sets item theCurrent as current
1241 */
1242 void SalomeApp_EntityEdit::insertList(const TColStd_ListOfInteger& theList,
1243                                 const int                    theCurrent)
1244 {
1245   if (myCombo)
1246     myCombo->insertList(theList);
1247
1248   TColStd_ListIteratorOfListOfInteger aIter(theList);
1249   for (unsigned i = 0; aIter.More(); aIter.Next(), i++) {
1250     if (theCurrent == i) {
1251       setText(QString::number(aIter.Value()));
1252       break;
1253     }
1254   }
1255 }
1256
1257 /*!
1258   Adds item in combo box, sets it current if theSetCurrent is true
1259 */
1260 void SalomeApp_EntityEdit::insertItem(const double theValue,
1261                                 bool         theSetCurrent)
1262 {
1263   if (myCombo) {
1264     myCombo->insertItem(theValue);
1265   }
1266   if (theSetCurrent)
1267     setText(QString::number(theValue));
1268 }
1269
1270 /*!
1271   Adds items in combo box, sets item theCurrent as current
1272 */
1273 void SalomeApp_EntityEdit::insertList(const TColStd_ListOfReal& theList,
1274                                 const int                 theCurrent)
1275 {
1276   if (myCombo)
1277     myCombo->insertList(theList);
1278
1279   TColStd_ListIteratorOfListOfReal aIter(theList);
1280   for (unsigned i = 0; aIter.More(); aIter.Next(), i++) {
1281     if (theCurrent == i) {
1282       setText(QString::number(aIter.Value()));
1283       break;
1284     }
1285   }
1286 }
1287
1288 /*! 
1289   \return actual widget
1290 */
1291 QWidget* SalomeApp_EntityEdit::getControl()
1292 {
1293   if (myEdit)
1294     return myEdit;
1295   else if (myCombo)
1296     return myCombo;
1297   else
1298     return 0;
1299 }
1300
1301 /*!
1302   redirect focus to corresponding widget
1303 */
1304 void SalomeApp_EntityEdit::setFocus()
1305 {
1306   if (myEdit) {
1307     myEdit->setFocus();
1308     //myEdit->selectAll();
1309   }
1310   else if (myCombo && myCombo->isEditable()) {
1311     myCombo->setFocus();
1312     //myCombo->lineEdit()->selectAll();
1313   }
1314 }
1315
1316 /*!
1317   Sets validator for the control
1318 */
1319 void SalomeApp_EntityEdit::setValidator(const QValidator* theValidator)
1320 {
1321   if (myEdit)
1322     myEdit->setValidator(theValidator);
1323   if (myCombo)
1324     myCombo->setValidator(theValidator);
1325 }
1326
1327 /*!
1328   Event filter for KeyPress event
1329 */
1330 void SalomeApp_EntityEdit::keyPressEvent( QKeyEvent * e)
1331 {
1332   if ( (e->key() == Qt::Key_Enter ||
1333         e->key() == Qt::Key_Return ) )
1334     onApply();
1335   else if (e->key() == Qt::Key_Escape)
1336     onCancel();
1337 }
1338
1339 /*!
1340   Called when item activated in combo box
1341 */
1342 void SalomeApp_EntityEdit::onComboActivated(const QString& theText)
1343 {
1344   onTextChanged(theText);
1345 }
1346
1347 /*!
1348   Slot, called when text changed in line edit
1349 */
1350 void SalomeApp_EntityEdit::onTextChanged(const QString& theText)
1351 {
1352   if (myApplyBtn)
1353     myApplyBtn->setEnabled(!(theText == myString));
1354   if (myCancelBtn)
1355     myCancelBtn->setEnabled(!(theText == myString));
1356 }
1357
1358 /*!
1359   Slot, called when user presses Cancel button
1360 */
1361 void SalomeApp_EntityEdit::onCancel()
1362 {
1363   setText(myString);
1364   if (myApplyBtn)
1365     myApplyBtn->setEnabled(false);
1366   if (myCancelBtn)
1367     myCancelBtn->setEnabled(false);
1368   emit escapePressed();
1369 }
1370
1371 /*!
1372   Slot, called when user presses Apply button
1373 */
1374 void SalomeApp_EntityEdit::onApply()
1375 {
1376   myString = getText();
1377   if (myApplyBtn)
1378     myApplyBtn->setEnabled(false);
1379   if (myCancelBtn)
1380     myCancelBtn->setEnabled(false);
1381   emit returnPressed();
1382 }
1383
1384 /*!
1385   Shows/hides buttons
1386 */
1387 void SalomeApp_EntityEdit::showButtons(bool show)
1388 {
1389   if (myApplyBtn)
1390     show ? myApplyBtn->show()  : myApplyBtn->hide();
1391   if (myCancelBtn)
1392     show ? myCancelBtn->show() : myCancelBtn->hide();
1393 }
1394
1395 /*!
1396   Enables/disables data duplication (for combo box)
1397 */
1398 void SalomeApp_EntityEdit::setDuplicatesEnabled(bool enabled)
1399 {
1400   if (myCombo)
1401     myCombo->setDuplicatesEnabled(enabled);
1402 }