Salome HOME
Join modifications from branch BR_DEBUG_3_2_0b1
[modules/gui.git] / src / SalomeApp / SalomeApp_ListView.cxx
1 // Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
2 // 
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either 
6 // version 2.1 of the License.
7 // 
8 // This library is distributed in the hope that it will be useful 
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public  
14 // License along with this library; if not, write to the Free Software 
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 //  SALOME SalomeApp
20 //
21 //  File   : SalomeApp_ListView.cxx
22 //  Author : Vadim SANDLER
23 //  Module : SALOME
24 //  $Header$
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 <qheader.h>
33 #include <qvalidator.h>
34 #include <qapplication.h>
35 #include <qtoolbutton.h>
36
37 #include <TColStd_ListIteratorOfListOfInteger.hxx>
38 #include <TColStd_ListIteratorOfListOfReal.hxx>
39
40 #include "utilities.h"
41
42 using namespace std;
43
44 /*!
45   Used for resizing editing widget
46 */
47 void computeEditGeometry(SalomeApp_ListViewItem* theItem,
48                          SalomeApp_EntityEdit*   theWidget)
49 {
50   if (!theItem)
51     return;
52   QListView* aListView = theItem->listView();
53   int anEditColumn = theItem->getEditedColumn();
54   if (anEditColumn < 0)
55     return;
56
57   int aX = 0, aY = 0, aW = 0, aH = 0;
58
59   QRect aRect = aListView->itemRect(theItem);
60   aListView->contentsToViewport(aListView->header()->sectionPos(anEditColumn), 0, aX, aY);
61   if (aX < 0)
62     aX = 0; // THIS CAN BE REMOVED
63   QSize aSize = theWidget->getControl()->sizeHint();
64   aH = QMAX(aSize.height() , aRect.height() );
65   aY = aRect.y() - ((aH - aRect.height()) / 2);
66   //aW = aListView->columnWidth(anEditColumn); // CAN SUBSTITUTE NEXT 3 ROWS
67   aW = aListView->viewport()->width() - aX;
68   if (aW < 0)
69     aW = 0;
70   theWidget->setGeometry(aX, aY, aW, aH);
71 }
72
73 /*!
74   Constructor
75 */
76 SalomeApp_ListView::SalomeApp_ListView( QWidget* parent )
77 : QtxListView( parent )
78 {
79   myMouseEnabled = true;
80   myEditingEnabled = false;
81   setSelectionMode(Single);
82   setSorting(-1);
83   setRootIsDecorated(false);
84   setAllColumnsShowFocus(false);
85 //  header()->setClickEnabled(false);
86   header()->setMovingEnabled(false);
87
88   myEditedItem = 0;
89   myEdit = 0;
90
91   viewport()->installEventFilter(this);
92
93   connect(this, SIGNAL(selectionChanged()),
94           this, SLOT(onSelectionChanged()));
95   connect(header(), SIGNAL(sizeChange(int, int, int)),
96           this,     SLOT(onHeaderSizeChange(int, int, int)));
97 }
98
99 /*!
100   Destructor
101 */
102 SalomeApp_ListView::~SalomeApp_ListView()
103 {
104   if (myEdit) {
105     delete myEdit;
106   }
107   myEdit = 0;
108   myEditedItem = 0;
109 }
110
111 /*!
112   Updates all data viewer
113 */
114 void SalomeApp_ListView::updateViewer()
115 {
116   // temporary disconnecting selection changed SIGNAL
117   blockSignals(true);
118   SalomeApp_ListViewItem* aRoot = (SalomeApp_ListViewItem*)firstChild();
119   if (aRoot)
120     aRoot->updateAllLevels();
121   updateContents();
122   // connecting again selection changed SIGNAL
123   blockSignals(false);
124   emit selectionChanged();
125 }
126
127 /*!
128   Updates currently selected item(s)
129 */
130 void SalomeApp_ListView::updateSelected()
131 {
132   // temporary disconnecting selection changed SIGNAL
133   blockSignals(true);
134   SalomeApp_ListViewItem* aChild = (SalomeApp_ListViewItem*)selectedItem();
135   if (aChild)
136     aChild->updateAllLevels();
137   updateContents();
138   // connecting again selection changed SIGNAL
139   blockSignals(false);
140   emit selectionChanged();
141 }
142
143 /*!
144   Returns popup client type
145 */
146 QString SalomeApp_ListView::popupClientType() const
147 {
148   return "SalomeApp_ListView";
149 }
150
151 /*!
152   Fills popup menu with items
153 */
154 void SalomeApp_ListView::contextMenuPopup( QPopupMenu* aPopup )
155 {
156   if (aPopup) {
157     // add items here...
158   }
159 }
160
161 /*!
162   Clears view
163 */
164 void SalomeApp_ListView::clear()
165 {
166   if (myEdit) {
167     delete myEdit;
168     myEdit = 0;
169     myEditedItem = 0;
170   }
171   QListView::clear();
172 }
173
174 /*!
175   \return true if mouse events are enabled
176 */
177 bool SalomeApp_ListView::isMouseEnabled()
178 {
179   return myMouseEnabled;
180 }
181
182 /*!
183   Enables/disables mouse events (excluding MouseMove)
184 */
185 void SalomeApp_ListView::enableMouse(bool enable)
186 {
187   myMouseEnabled = enable;
188 }
189
190 /*!
191   Event filter
192 */
193 bool SalomeApp_ListView::eventFilter(QObject* object, QEvent* event)
194 {
195   if (object == viewport() &&
196        (event->type() == QEvent::MouseButtonPress   ||
197         event->type() == QEvent::MouseButtonRelease ||
198         event->type() == QEvent::MouseButtonDblClick)  &&
199       !isMouseEnabled())
200     return true;
201   else
202     return QListView::eventFilter(object, event);
203 }
204
205 /*!
206   Setting editing of items availbale/not available
207 */
208 void SalomeApp_ListView::enableEditing(bool theFlag)
209 {
210   myEditingEnabled = theFlag;
211   if (!myEditingEnabled) {
212     if (myEdit) {
213       delete myEdit;
214       myEdit = 0;
215       myEditedItem = 0;
216     }
217   }
218 }
219
220 /*!
221   Says if editing is enabled
222 */
223 bool SalomeApp_ListView::isEnableEditing()
224 {
225   return myEditingEnabled;
226 }
227
228 /*!
229   Calls finishEditing(true)...
230 */
231 void SalomeApp_ListView::accept()
232 {
233   finishEditing(true);
234 }
235
236 /*!
237   Slot, called when selection changed in List Viewer
238 */
239 void SalomeApp_ListView::onSelectionChanged()
240 {
241   if (myEdit) {
242     finishEditing(true);
243     delete myEdit;
244     myEdit = 0;
245     if (myEditedItem && !myEditedItem->isAccepted()) {
246       delete myEditedItem;
247       updateContents();
248     }
249     myEditedItem = 0;
250   }
251   // editing is allowed in Single Selection Mode only
252   if (selectionMode() != Single || !isEnableEditing())
253     return;
254   SalomeApp_ListViewItem* anItem = (SalomeApp_ListViewItem*)selectedItem();
255   if (anItem) {
256     if (!anItem->isEditable())
257       return;
258     myEdit = anItem->startEditing();
259     if (myEdit) {
260       connect(myEdit, SIGNAL(returnPressed()), this, SLOT(onEditOk()));
261       connect(myEdit, SIGNAL(escapePressed()), this, SLOT(onEditCancel()));
262       myEditedItem = anItem;
263       myEdit->show();
264       myEdit->setFocus();
265     }
266   }
267 }
268
269 /*!
270   Called when Data Viewer is resized
271 */
272 void SalomeApp_ListView::resizeEvent( QResizeEvent * e)
273 {
274   QListView::resizeEvent(e);
275   int aW = columnWidth(columns()-1);
276   int aX = header()->sectionPos(columns()-1);
277   if (aW < width() - frameWidth() * 2 - aX - 1)
278     setColumnWidth(columns()-1, width() - frameWidth() * 2 - aX - 1);
279   updateContents();
280 }
281
282 /*!
283   Slot, called when columns sizes are changed
284 */
285 void SalomeApp_ListView::onHeaderSizeChange(int, int, int)
286 {
287   int aW = columnWidth(columns()-1);
288   int aX = header()->sectionPos(columns()-1);
289   if (aW < width() - frameWidth() * 2 - aX - 1)
290     setColumnWidth(columns()-1, width() - frameWidth() * 2 - aX - 1);
291 }
292
293 /*!
294   Handler for paint event
295 */
296 void SalomeApp_ListView::viewportPaintEvent(QPaintEvent* e)
297 {
298   QListView::viewportPaintEvent(e);
299   if (myEditedItem && myEdit) {
300     computeEditGeometry(myEditedItem, myEdit);
301   }
302 }
303
304 /*!
305   Called when user finishes in editing of item
306 */
307 void SalomeApp_ListView::onEditOk()
308 {
309   finishEditing(true);
310 }
311
312 /*!
313   Called when user cancels item editing
314 */
315 void SalomeApp_ListView::onEditCancel()
316 {
317   finishEditing(false);
318 }
319
320 /*!
321   Finishes editing of entity
322 */
323 UpdateType SalomeApp_ListView::finishEditing(bool ok)
324 {
325   UpdateType aNeedsUpdate = utCancel;
326   if (myEditedItem && myEdit)
327   {
328     disconnect(myEdit, SIGNAL(returnPressed()), this, SLOT(onEditOk()));
329     disconnect(myEdit, SIGNAL(escapePressed()), this, SLOT(onEditCancel()));
330     myEditedItem->setAccepted(true);
331     if (ok) {
332       aNeedsUpdate = myEditedItem->finishEditing(myEdit);
333       if (aNeedsUpdate == utCancel) {
334         // something to do here on Cancel...
335       }
336       else {
337         // something to do here on OK...
338       }
339       // updating contents
340       switch (aNeedsUpdate) {
341       case utUpdateItem:
342         {
343           if (myEditedItem)
344             myEditedItem->updateAllLevels();
345           break;
346         }
347       case utUpdateParent:
348         {
349           if (myEditedItem) {
350             SalomeApp_ListViewItem* aParent = (SalomeApp_ListViewItem*)(myEditedItem->parent());
351             if (aParent)
352               aParent->updateAllLevels();
353             else
354               myEditedItem->updateAllLevels();
355           }
356           break;
357         }
358       case utUpdateViewer:
359         {
360           updateViewer();
361           break;
362         }
363       case utUpdateAll:
364         {
365           // doing the same as for utUpdateViewer here
366           // descendants can add extra processing
367           updateViewer();
368           break;
369         }
370       default:
371         break;
372       }
373     }
374   }
375
376   // hide <myEdit> widget
377   if (myEdit) {
378     myEdit->hide();
379   }
380
381   return aNeedsUpdate;
382 }
383
384 /*!
385   \return current tooltip for list view
386   \retval valid rect in success
387 */
388 QRect SalomeApp_ListView::tip(QPoint aPos,
389                         QString& aText,
390                         QRect& dspRect,
391                         QFont& dspFnt) const
392 {
393   QRect result( -1, -1, -1, -1 );
394   SalomeApp_ListViewItem* aItem = (SalomeApp_ListViewItem*)itemAt( aPos );
395   if ( aItem ) {
396     for (int i = 0; i < columns(); i++) {
397       QRect aItemRect = aItem->itemRect(i);
398       QRect aTextRect = aItem->textRect(i);
399       if ( !aItem->text(i).isEmpty() &&
400            ( aItemRect.width()  > header()->sectionSize(i) ||
401              aTextRect.left()   < 0 ||
402              aTextRect.top()    < 0 ||
403              aTextRect.right()  > viewport()->width() ||
404              aTextRect.bottom() > viewport()->height() ) ) {
405         // calculating tip data
406         aText   = aItem->tipText();
407         dspRect = aItem->tipRect();
408         dspFnt  = font();
409         if (dspRect.isValid()) {
410           result  = QRect(QPoint(0, aItemRect.top()),
411                           QSize(viewport()->width(), aItemRect.height()));
412         }
413       }
414     }
415   }
416   return result;
417 }
418
419 /*!
420   Constructor
421 */
422 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListView* parent) :
423 QListViewItem( parent )
424 {
425   init();
426 }
427
428 /*!
429   Constructor
430 */
431 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListView*     parent,
432                                    SalomeApp_ListViewItem* after) :
433 QListViewItem( parent, after )
434 {
435   init();
436 }
437
438 /*!
439   Constructor
440 */
441 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListView*     parent,
442                                    const QString&    theName,
443                                    const bool        theEditable) :
444 QListViewItem(parent, theName)
445 {
446   init();
447   setEditable(theEditable);
448 }
449
450 /*!
451   Constructor
452 */
453 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListView*     parent,
454                                    const QString&    theName,
455                                    const QString&    theValue,
456                                    const bool        theEditable) :
457 QListViewItem(parent, theName, theValue)
458 {
459   init();
460   setEditable(theEditable);
461 }
462
463 /*!
464   Constructor
465 */
466 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListViewItem* parent,
467                                    const QString&    theName,
468                                    const bool        theEditable) :
469 QListViewItem(parent, theName)
470 {
471   init();
472   setEditable(theEditable);
473 }
474
475 /*!
476   Constructor
477 */
478 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListViewItem* parent,
479                                    SalomeApp_ListViewItem* after,
480                                    const QString&    theName,
481                                    const bool        theEditable) :
482 QListViewItem(parent, after, theName)
483 {
484   init();
485   setEditable(theEditable);
486 }
487
488 /*!
489   Constructor
490 */
491 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListView*     parent,
492                                    SalomeApp_ListViewItem* after,
493                                    const QString&    theName,
494                                    const bool        theEditable) :
495 QListViewItem(parent, after, theName)
496 {
497   init();
498   setEditable(theEditable);
499 }
500
501
502 /*!
503   Constructor
504 */
505 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListViewItem* parent,
506                                    const QString&    theName,
507                                    const QString&    theValue,
508                                    const bool        theEditable) :
509 QListViewItem(parent, theName, theValue)
510 {
511   init();
512   setEditable(theEditable);
513 }
514
515
516 /*!
517   Constructor
518 */
519 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListViewItem* 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   Constructor
532 */
533 SalomeApp_ListViewItem::SalomeApp_ListViewItem(SalomeApp_ListView*     parent,
534                                    SalomeApp_ListViewItem* after,
535                                    const QString&    theName,
536                                    const QString&    theValue,
537                                    const bool        theEditable) :
538 QListViewItem(parent, after, theName, theValue)
539 {
540   init();
541   setEditable(theEditable);
542 }
543
544 /*!
545   Destructor
546 */
547 SalomeApp_ListViewItem::~SalomeApp_ListViewItem()
548 {
549 }
550
551 /*!
552   Initialization
553 */
554 void SalomeApp_ListViewItem::init()
555 {
556   myEditable    = false;
557   myAccepted    = true;
558   myEditingType = (int)SalomeApp_EntityEdit::etLineEdit;
559   myValueType   = (int)SalomeApp_EntityEdit::vtString;
560   myButtons     = 0;
561   myUserType    = -1;
562 }
563
564 /*!
565   \return text in the first column
566 */
567 QString SalomeApp_ListViewItem::getName() const
568 {
569   return ( listView()->columns() > 0 ) ? text(0) : QString("");
570 }
571
572 /*!
573   Sets text in the first column
574 */
575 UpdateType SalomeApp_ListViewItem::setName(const QString& theName)
576 {
577   UpdateType aNeedsUpdate = utCancel;
578   if (listView()->columns() > 0) {
579     setText(0, theName);
580     aNeedsUpdate = utNone;
581   }
582   return aNeedsUpdate;
583 }
584
585 /*!
586   \return text in the second column
587 */
588 QString SalomeApp_ListViewItem::getValue() const
589 {
590   return ( listView()->columns() > 1 ) ? text(1) : QString("");
591 }
592
593 /*!
594   Sets text in the second column
595 */
596 UpdateType SalomeApp_ListViewItem::setValue(const QString& theValue)
597 {
598   UpdateType aNeedsUpdate = utCancel;
599   if (listView()->columns() > 1) {
600     setText(1, theValue);
601     aNeedsUpdate = utNone;
602   }
603   return aNeedsUpdate;
604 }
605
606 /*!
607   \return full path to the entity from the root
608 */
609 QString SalomeApp_ListViewItem::fullName()
610 {
611   QString aFullName = getName();
612   SalomeApp_ListViewItem* aParent = (SalomeApp_ListViewItem*)parent();
613   while(aParent != NULL) {
614     aFullName = aParent->getName() + QString(".") + aFullName;
615     aParent = (SalomeApp_ListViewItem*)(aParent->parent());
616   }
617   return aFullName;
618 }
619
620 /*!
621   expands all entities beginning from this level
622 */
623 void SalomeApp_ListViewItem::openAllLevels()
624 {
625   setOpen(true);
626   SalomeApp_ListViewItem* aChild = (SalomeApp_ListViewItem*)firstChild();
627   while( aChild ) {
628     aChild->openAllLevels();
629     aChild = (SalomeApp_ListViewItem*)(aChild->nextSibling());
630   }
631 }
632
633 /*!
634   update all entites beginning from this level
635 */
636 void SalomeApp_ListViewItem::updateAllLevels()
637 {
638   SalomeApp_ListViewItem* aChild = (SalomeApp_ListViewItem*)firstChild();
639   while( aChild ) {
640     aChild->updateAllLevels();
641     aChild = (SalomeApp_ListViewItem*)(aChild->nextSibling());
642   }
643 }
644
645 /*!
646   \return true if entity is editable
647 */
648 bool SalomeApp_ListViewItem::isEditable() const
649 {
650   return myEditable;
651 }
652
653 /*!
654   Sets editable flag fo the entity
655 */
656 void SalomeApp_ListViewItem::setEditable(bool theEditable)
657 {
658   myEditable = theEditable;
659 }
660
661 /*!
662   \return true if entitiy is accepted after editing
663 */
664 bool SalomeApp_ListViewItem::isAccepted() const
665 {
666   return myAccepted;
667 }
668
669 /*!
670   Sets entitiy accepted or not after editing
671 */
672 void SalomeApp_ListViewItem::setAccepted(bool theAccepted)
673 {
674   myAccepted = theAccepted;
675 }
676
677 /*!
678  \retval type of edit control (default is edit box)
679       \li 0 - edit box
680       \li 1 - combo box
681       \li 2 - editable combo box
682 */
683 int SalomeApp_ListViewItem::getEditingType()
684 {
685   return myEditingType;
686 }
687
688 /*!
689  \retval type of edit control (negative value means none)
690      \li 0 - edit box
691      \li 1 - combo box
692      \li 2 - editable combo box
693 */
694 void SalomeApp_ListViewItem::setEditingType(const int type)
695 {
696   myEditingType = type;
697 }
698
699 /*! \retval edited column, default is last column
700     negative value means there are no editable columns
701 */
702 int SalomeApp_ListViewItem::getEditedColumn()
703 {
704   return listView()->columns()-1;
705 }
706
707 /*!
708   \retval type of edited value (string, int, double)
709    default is string
710 */
711 int SalomeApp_ListViewItem::getValueType()
712 {
713   return myValueType;
714 }
715
716 /*!
717   Sets type of edited value
718 */
719 void SalomeApp_ListViewItem::setValueType(const int valueType)
720 {
721   myValueType = valueType;
722 }
723
724 /*!
725   Sets type of edited value
726 */
727 int SalomeApp_ListViewItem::getUserType()
728 {
729   return myUserType;
730 }
731
732 /*!
733   Sets type of edited value
734 */
735 void SalomeApp_ListViewItem::setUserType(const int userType)
736 {
737   myUserType = userType;
738 }
739
740 /*!
741   \return buttons for editing widget (Apply (V), Cancel (X))
742    default is both buttons
743 */
744 int SalomeApp_ListViewItem::getButtons()
745 {
746   return myButtons;
747 }
748
749 /*!
750   Sets buttons for editing widget (Apply (V), Cancel (X))
751 */
752 void SalomeApp_ListViewItem::setButtons(const int buttons)
753 {
754   myButtons = buttons;
755 }
756
757 /*!
758   Creates control for editing and fills it with values
759 */
760 SalomeApp_EntityEdit* SalomeApp_ListViewItem::startEditing()
761 {
762   SalomeApp_EntityEdit* aWidget = 0;
763   QListView* aListView = listView();
764   if (aListView) {
765     if (!isEditable())
766       return 0;
767     int anEditType   = getEditingType();
768     int aValueType   = getValueType();
769     int aButtons     = getButtons();
770     int anEditColumn = getEditedColumn();
771     if (anEditColumn < 0 || anEditType < 0)
772       return 0;
773     aWidget = new SalomeApp_EntityEdit(aListView->viewport(),
774                                  anEditType,
775                                  aValueType,
776                                  aButtons & SalomeApp_EntityEdit::btApply,
777                                  aButtons & SalomeApp_EntityEdit::btCancel);
778     computeEditGeometry(this, aWidget);
779
780     fillWidgetWithValues(aWidget);
781   }
782   return aWidget;
783 }
784
785 /*!
786   Fills widget with initial values (list or single value)
787 */
788 void SalomeApp_ListViewItem::fillWidgetWithValues(SalomeApp_EntityEdit* theWidget)
789 {
790   int anEditColumn = getEditedColumn();
791   if (theWidget && anEditColumn >= 0 && !text(anEditColumn).isEmpty())
792     theWidget->insertItem(text(anEditColumn), true);
793 }
794
795 /*!
796   Finishes editing of entity
797 */
798 UpdateType SalomeApp_ListViewItem::finishEditing(SalomeApp_EntityEdit* theWidget)
799 {
800   UpdateType aNeedsUpdate = utCancel;
801   try {
802     if (theWidget) {
803       int anEditColumn = getEditedColumn();
804       switch (anEditColumn) {
805       case 0:
806         aNeedsUpdate = setName(theWidget->getText());
807         break;
808       case 1:
809         aNeedsUpdate = setValue(theWidget->getText());
810         break;
811       default:
812         break;
813       }
814     }
815   }
816   catch (...) {
817     MESSAGE( "System error has been caught - SalomeApp_ListViewItem::finishEditing" )
818   }
819   return aNeedsUpdate;
820 }
821
822 /*!
823   Calculates rectangle which should contain item's tip
824 */
825 QRect SalomeApp_ListViewItem::tipRect()
826 {
827   QRect aRect = QRect(-1, -1, -1, -1);
828   QRect aItemRect = listView()->itemRect(this);
829   if ( !aItemRect.isValid() )
830     return aItemRect;
831
832   QString aTip = tipText();
833   if (!aTip.isEmpty()) {
834     QRect aRect0 = textRect(0);
835     QFont aFont(listView()->font());
836     QFontMetrics fm(aFont);
837     int iw = fm.width(aTip);
838     aRect = QRect(QPoint(aRect0.x() < 0 ? 0 : aRect0.x(),
839                          aRect0.y()),
840                   QSize (iw,
841                          aRect0.height()));
842   }
843   return aRect;
844 }
845
846 /*!
847   \return text for tooltip
848 */
849 QString SalomeApp_ListViewItem::tipText()
850 {
851   QString aText = getName();
852   if (!getValue().isEmpty())
853     aText += QString(" : ") + getValue();
854   return aText;
855 }
856
857 /*!
858   Calculates rect of item text in viewport coordinates
859 */
860 QRect SalomeApp_ListViewItem::textRect(const int column) const
861 {
862   QRect aItemRect = listView()->itemRect( this );
863   if ( !aItemRect.isValid() )
864     return aItemRect;
865
866   QFont aFont(listView()->font());
867   QFontMetrics fm(aFont);
868
869   int decorWidth  = ( listView()->rootIsDecorated() ) ?
870                     ( listView()->treeStepSize() * (depth() + 1) ) :
871                     ( listView()->treeStepSize() *  depth() );
872   int pixmapWidth = ( pixmap(column) ) ?
873                       pixmap(column)->width() +  listView()->itemMargin() * 2 :
874                       listView()->itemMargin();
875   int prevWidth = 0;
876   for (int i = 0; i < column; i++)
877     prevWidth += listView()->header()->sectionSize(i);
878   int ix = prevWidth   +
879            pixmapWidth +
880            ((column == 0) ? decorWidth : 0);
881   int iy = aItemRect.y();
882   int iw = fm.width(text(column));
883   int ih = aItemRect.height();
884   if (pixmap(column)) {
885     iy += listView()->itemMargin();
886     ih -= listView()->itemMargin() * 2;
887   }
888   ix -= listView()->contentsX();
889
890   QRect theResult(QPoint(ix, iy), QSize(iw, ih));
891   return theResult;
892 }
893
894 /*!
895   Calculates rect of item data in viewport coordinates
896 */
897 QRect SalomeApp_ListViewItem::itemRect(const int column) const
898 {
899   QRect aItemRect = listView()->itemRect( this );
900   if ( !aItemRect.isValid() )
901     return aItemRect;
902
903   QFont aFont(listView()->font());
904   QFontMetrics fm(aFont);
905
906   int decorWidth  = ( listView()->rootIsDecorated() ) ?
907                     ( listView()->treeStepSize() * (depth() + 1) ) :
908                     ( listView()->treeStepSize() *  depth() );
909   int pixmapWidth = ( pixmap(column) ) ?
910                       pixmap(column)->width() +  listView()->itemMargin() * 2 :
911                       0;
912   int prevWidth = 0;
913   for (int i = 0; i < column; i++)
914     prevWidth += listView()->header()->sectionSize(i);
915   int ix = prevWidth;
916   int iy = aItemRect.y();
917   int iw = pixmapWidth +
918            listView()->itemMargin() * 2 +
919            ((column == 0) ? decorWidth : 0) +
920            fm.width(text(column));
921   int ih = aItemRect.height();
922   ix -= listView()->contentsX();
923
924   QRect theResult(QPoint(ix, iy), QSize(iw, ih));
925   return theResult;
926 }
927
928 /*!
929   Constructor
930 */
931 SalomeApp_EditBox::SalomeApp_EditBox(QWidget* parent) :
932 QLineEdit(parent)
933 {
934 }
935
936 /*!
937   Event filter for key pressing
938 */
939 void SalomeApp_EditBox::keyPressEvent( QKeyEvent *e )
940 {
941   if ( e->key() == Key_Escape )
942     emit escapePressed();
943   else
944     QLineEdit::keyPressEvent( e );
945   e->accept();
946 }
947
948
949 /*!
950   Constructor
951 */
952 SalomeApp_ComboBox::SalomeApp_ComboBox(bool rw, QWidget* parent, const char* name) :
953 QComboBox(rw, parent, name)
954 {
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 (text(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(theValue, theIndex);
976 }
977
978 /*!
979   Adds list of items in combo box
980 */
981 void SalomeApp_ComboBox::insertList(const QStringList& theList)
982 {
983   for (unsigned 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 = text(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 = text(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->setInsertionPolicy(QComboBox::NoInsertion);
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( "STD", tr( "ICON_APPLY" ), false );
1114
1115     myApplyBtn->setPixmap(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( "STD", tr( "ICON_CANCEL" ), false );
1129     myCancelBtn->setPixmap(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->setCurrentItem(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->currentItem();
1200     else if (theOrder == atAfterCurrent &&
1201              myCombo->count() > 0 &&
1202              myCombo->currentItem() < myCombo->count()-1)
1203       aIndexAt = myCombo->currentItem() + 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 == i) {
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 == i) {
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->editable()) {
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() == Key_Enter ||
1329         e->key() == Key_Return ) )
1330     onApply();
1331   else if (e->key() == 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 }