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