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