Salome HOME
Update from BR_V5_DEV 13Feb2009
[modules/gui.git] / src / ObjBrowser / OB_Browser.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 // File   : OB_Browser.cxx
23 // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
24 //
25 #include "OB_Browser.h"
26
27 //#include "OB_Filter.h"
28 //#include "OB_ListItem.h"
29 //#include "OB_ListView.h"
30
31 #include <QtxTreeView.h>
32 #include <QtxSearchTool.h>
33 //#include <SUIT_DataObjectIterator.h>
34
35 #include <QAction>
36 #include <QMenu>
37 #include <QItemSelection>
38 #include <QKeyEvent>
39 #include <QVBoxLayout>
40 #include <QAbstractItemModel>
41 #include <QAbstractItemDelegate>
42 #include <QHeaderView>
43
44 #include <time.h>
45
46
47 /*!
48   \class  OB_Browser::ToolTip
49   Tool tip for OB_Browser.
50 */
51
52 //TODO: ToolTip commented - to be removed or revised
53 /*
54 class OB_Browser::ToolTip : public QToolTip
55 {
56 public:
57   ToolTip( OB_Browser* b, QWidget* p = 0 );
58   virtual ~ToolTip();
59
60   void        maybeTip( const QPoint& );
61
62 private:
63   OB_Browser* myBrowser;
64 };
65 */
66 /*!
67   Constructor
68 */
69 /*
70 OB_Browser::ToolTip::ToolTip( OB_Browser* b, QWidget* p )
71 : QToolTip( p ),
72 myBrowser( b )
73 {
74 }
75 */
76 /*!
77   Destructor
78 */
79 /*
80 OB_Browser::ToolTip::~ToolTip()
81 {
82 }
83 */
84 /*!
85   It is called when there is a possibility that a tool tip
86   should be shown and must decide whether there is a tool tip for the point
87   in the widget that this QToolTip object relates to.
88   \param pos - point co-ordinates
89 */
90 /*
91 void OB_Browser::ToolTip::maybeTip( const QPoint& pos )
92 {
93   if ( !parentWidget() || !myBrowser || !myBrowser->isShowToolTips() )
94           return;
95
96   QListView* lv = myBrowser->listView();
97
98   QListViewItem* item = lv->itemAt( pos );
99   SUIT_DataObject* obj = myBrowser->dataObject( item );
100   if ( !obj )
101     return;
102
103   QString aText = obj->toolTip();
104
105   if ( aText.isEmpty() )
106     return;
107
108   QRect aRect = lv->itemRect( item );
109
110   tip( aRect, aText );
111 }
112 */
113
114
115 /*!
116   \class OB_Browser
117   \brief Object browser widget which can be used to handle tree-like data model.
118
119   The class OB_Browser implements public API of an object browser widget
120   that can be used to display arbitrary application data in a hierarchical form.
121   It is based on Qt4 model/view architecture. 
122
123   Object browser can be used with conjuction of any custom item model inherited
124   from QAbstractItemModel class (see Qt 4 reference manual).
125
126   The class provides a functionality get/modify selection, drag-n-drop of the
127   objects, etc.
128 */
129
130 /*!
131   \brief Constructor
132   \param parent paren widget
133   \param model data model
134 */
135 OB_Browser::OB_Browser( QWidget* parent, QAbstractItemModel* model )
136 : QWidget( parent ),
137   myAutoOpenLevel( 0 )
138 {
139   myView = new QtxTreeView( this );
140   myView->setRootIsDecorated( true );
141   myView->setSelectionMode( QAbstractItemView::ExtendedSelection );
142   myView->setAllColumnsShowFocus( true );
143
144   mySearchTool = new QtxSearchTool( this, myView );
145   mySearchTool->setFrameStyle( QFrame::NoFrame | QFrame::Plain );
146   mySearchTool->setActivators( QtxSearchTool::StandardKey | QtxSearchTool::SlashKey );
147   mySearchTool->setSearcher( new QtxTreeViewSearcher( myView ) );
148   
149   QVBoxLayout* main = new QVBoxLayout( this );
150   main->addWidget( myView );
151   main->addWidget( mySearchTool );
152   main->setMargin( 0 );
153   main->setSpacing( 3 );
154
155   // TODO: decide what to do with tooltip
156   //myShowToolTips = true;
157   //myTooltip = new ToolTip( this, myView->viewport() );
158
159   // TODO: drag-n-drop works differently - SUIT_TreeModel to be updated
160   // and QTreeView needs some setup
161   //connect( myView, SIGNAL( dropped( QPtrList<QListViewItem>, QListViewItem*, int ) ),
162   //         this, SLOT( onDropped( QPtrList<QListViewItem>, QListViewItem*, int ) ) );
163   setModel( model );
164
165   connect( myView, SIGNAL( selectionChanged() ),
166            this,   SIGNAL( selectionChanged() ) );
167
168 }
169
170 /*!
171   \brief Destructor.
172 */
173 OB_Browser::~OB_Browser()
174 {
175   //delete myTooltip;
176   //setUpdater( 0 );
177 }
178
179 /*!
180   \brief Get data model.
181   \return data model
182   \sa setModel()
183 */
184 QAbstractItemModel* OB_Browser::model() const
185 {
186   return myView->model();
187 }
188
189 /*!
190   \brief Set data model.
191   \param model data model
192   \sa model()
193 */
194 void OB_Browser::setModel( QAbstractItemModel* model )
195 {
196   myView->setModel( model );
197   myView->update();
198   setModified();
199 }
200
201 /*!
202   \brief Get current item delegate (items renderer).
203   \return currently used item delegate
204   \sa setItemDelegate()
205 */
206 QAbstractItemDelegate* OB_Browser::itemDelegate() const
207 {
208   return myView->itemDelegate();
209 }
210
211 /*!
212   \brief Set item delegate (items renderer).
213   \param d custom item delegate
214   \sa itemDelegate()
215 */
216 void OB_Browser::setItemDelegate( QAbstractItemDelegate* d )
217 {
218   myView->setItemDelegate( d );
219 }
220
221 /*!
222   \brief Check if controls for expanding and collapsing top-level items are shown.
223   \return \c true if top-level items are decorated
224   \sa setRootIsDecorated()
225 */
226 bool OB_Browser::rootIsDecorated() const
227 {
228   return myView->rootIsDecorated();
229 }
230
231 /*!
232   \brief Show/hide controls for expanding and collapsing top-level items.
233   \param decor if \c true, top-level items are decorated
234   \sa rootIsDecorated()
235 */
236 void OB_Browser::setRootIsDecorated( const bool decor )
237 {
238   if ( decor != rootIsDecorated() )
239     myView->setRootIsDecorated( decor );
240 }
241
242 /*
243   \brief Check if "Sorting" popup menu command for the header is enabled.
244   \return \c true if "Sorting" menu command is enabled
245   \sa setSortMenuEnabled()
246 */
247 bool OB_Browser::sortMenuEnabled() const
248 {
249   return myView->sortMenuEnabled();
250 }
251
252 /*
253   \brief Enable/disable "Sorting" popup menu command for the header.
254   \param enableSortMenu if \c true, enable "Sorting" menu command
255   \sa sortMenuEnabled()
256 */
257 void OB_Browser::setSortMenuEnabled( const bool enabled )
258 {
259   if ( enabled != sortMenuEnabled() )
260     myView->setSortMenuEnabled( enabled );
261 }
262
263 /*!
264   \brief Get search tool widget.
265   \return search tool widget
266   \sa isSearchToolEnabled(), setSearchToolEnabled()
267 */
268 QtxSearchTool* OB_Browser::searchTool() const
269 {
270   return mySearchTool;
271 }
272
273 /*!
274   \brief Check if search tool is enabled.
275   \return \c true if search tool is enabled
276   \sa setSearchToolEnabled(), searchTool()
277 */
278 bool OB_Browser::isSearchToolEnabled() const
279 {
280   return mySearchTool->isEnabled();
281 }
282
283 /*!
284   \brief Enable/disable search tool.
285   \param enable pass \c true to enable search tool
286   \sa isSearchToolEnabled(), searchTool()
287 */
288 void OB_Browser::setSearchToolEnabled( const bool enable )
289 {
290   if ( mySearchTool->isEnabled() == enable )
291     return;
292
293   mySearchTool->setEnabled( enable );
294   if ( !mySearchTool->isEnabled() )
295     mySearchTool->hide();
296 }
297
298 /*!
299   \brief Get number of levels which should be automatically expanded
300   when updating the data tree.
301   \return number of levels to be auto-opened on tree updating
302   \sa setAutoOpenLevel()
303 */
304 int OB_Browser::autoOpenLevel() const
305 {
306   return myAutoOpenLevel;
307 }
308
309 /*!
310   \brief Set number of levels which should be automatically expanded
311   when updating the data tree.
312   \param levels number of levels to be auto-opened on tree updating
313   \sa autoOpenLevel()
314 */
315 void OB_Browser::setAutoOpenLevel( const int levels )
316 {
317   if ( myAutoOpenLevel != levels )
318     myAutoOpenLevel = levels;
319 }
320
321 /*!
322   \brief Expand all branches to the specified number of levels.
323
324   If \a levels value is negative, then autoOpenLevel() value is used instead.
325   
326   \param levels number of levels to be expanded
327   \sa autoOpenLevel()
328 */
329 void OB_Browser::openLevels( const int levels )
330 {
331   myView->expandLevels( levels < 0 ? autoOpenLevel() : levels );
332 }
333
334 /*!
335   \return state "are tooltips shown"
336 */
337 /*
338 bool OB_Browser::isShowToolTips()
339 {
340   return myShowToolTips;
341 }
342 */
343 /*!
344   Sets new value of state "are tooltips shown"
345   \param theDisplay - new value
346 */
347 /*
348 void OB_Browser::setShowToolTips( const bool theDisplay )
349 {
350   myShowToolTips = theDisplay;
351 }
352 */
353
354 /*!
355   \brief Get number of selected items.
356   \return number of selected items
357 */
358 int OB_Browser::numberOfSelected() const
359 {
360   return myView->selectionModel() ? myView->selectionModel()->selectedIndexes().count() : 0;
361 }
362
363 /*!
364   \brief Get all selected items.
365   \return unsorted list of selected indexes with no duplicates
366 */
367 QModelIndexList OB_Browser::selectedIndexes() const
368 {
369   return myView->selectionModel() ? myView->selectionModel()->selectedIndexes() : QModelIndexList();
370 }
371
372 /*!
373   \brief Get selection containing information about selected ranges.
374   \return QItemSelection instance
375 */
376 const QItemSelection OB_Browser::selection() const
377 {
378   static QItemSelection emptySel;
379   QItemSelection sel = emptySel;
380   if ( myView->selectionModel() )
381     sel = myView->selectionModel()->selection();
382   return sel;
383 }
384
385 /*!
386   \brief Select/deselect specified model index.
387   \param index model index to be selected/deselected
388   \param on if \c true, the index will be selected, otherwise - deselected
389   \param keepSelection if \c true (default) the previous selection is kept, 
390   otherwise it is first cleared
391 */
392 void OB_Browser::select( const QModelIndex& index, const bool on, const bool keepSelection )
393 {
394   if ( myView->selectionModel() ) {
395     QItemSelectionModel::SelectionFlags f = on ? QItemSelectionModel::Select : QItemSelectionModel::Deselect;
396     f = f | QItemSelectionModel::Rows;
397     if ( !keepSelection )
398       f = f | QItemSelectionModel::Clear;
399
400     myView->selectionModel()->select( index, f );
401   }
402 }
403
404 /*!
405   \brief Select/deselect specified model indices.
406   \param indexes model indices to be selected/deselected
407   \param on if \c true, the indices will be selected, otherwise - deselected
408   \param keepSelection if \c true (default) the previous selection is kept, 
409   otherwise it is first cleared
410 */
411 void OB_Browser::select( const QModelIndexList& indexes, const bool on, const bool keepSelection )
412 {
413   bool blocked = myView->signalsBlocked();
414   myView->blockSignals( true );
415
416   QModelIndex idx;
417   bool first = true;
418
419   if ( !indexes.isEmpty() ) {
420     foreach( idx, indexes ) {
421       select( idx, on, first ? keepSelection : true );
422       first = false;
423     }
424   }
425   else if ( !keepSelection ) {
426     myView->clearSelection();
427   }
428
429   myView->blockSignals( blocked );
430   emit( selectionChanged() );
431 }
432
433 /*!
434   \brief Check if specified model index is expanded or collapsed.
435   \param index model index
436   \return \c true if model index is expanded
437   \sa setOpen()
438 */
439 bool OB_Browser::isOpen( const QModelIndex& index ) const
440 {
441   return index.isValid() && model() && model()->hasChildren( index ) && myView->isExpanded( index );
442 }
443
444 /*!
445   \brief Expand/collapse the specified model index.
446   \param index model index
447   \param open if \c true, the index will be expanded, otherwse - collapsed
448   \sa isOpen()
449 */
450 void OB_Browser::setOpen( const QModelIndex& index, const bool open )
451 {
452   myView->setExpanded( index, open );  // hasChildren() ???
453 }
454
455 /*!
456   \brief Adjust first column width to its contents.
457 */
458 void OB_Browser::adjustWidth()
459 {
460   myView->resizeColumnToEncloseContents( 0 );
461 }
462
463 /*!
464   \brief Adjust first column width to its contents.
465 */
466 void OB_Browser::adjustFirstColumnWidth()
467 {
468   myView->resizeColumnToEncloseContents( 0 );
469 }
470
471 /*!
472   \brief Adjust all columns width to its contents except the first column.
473 */
474 void OB_Browser::adjustColumnsWidth()
475 {
476   for ( int aCol = 1; aCol < myView->header()->count(); aCol++ ) {
477     if ( myView->columnWidth( aCol ) > 0 )
478       myView->resizeColumnToEncloseContents( aCol );
479   }
480 }
481
482 /*!
483   \return SUIT object correspondint to item at position 'pos'
484   \param pos - position
485 */
486 /* TODO: removed - QTreeView::indexAt() should be used
487 SUIT_DataObject* OB_Browser::dataObjectAt( const QPoint& pos ) const
488 {
489   SUIT_DataObject* obj = 0;
490
491   QListView* lv = listView();
492   if ( lv )
493     obj = dataObject( lv->itemAt( pos ) );
494
495   return obj;
496 }
497 */
498 /*!
499   \return filter of list view
500 */
501 /* TODO: removed
502 OB_Filter* OB_Browser::filter() const
503 {
504   return myView->filter();
505 }
506 */
507 /*!
508   Changes filter of list view
509   \param f - new filter
510 */
511 /* TODO: removed
512 void OB_Browser::setFilter( OB_Filter* f )
513 {
514   myView->setFilter( f );
515 }
516 */
517 /*!
518   Sets global width mode
519   \param mode - new width mode
520 */
521 /* TODO: removed
522 void OB_Browser::setWidthMode( QListView::WidthMode mode )
523 {
524   for ( int i = 0, n = myView->columns(); i < n; i++ )
525     if( mode!=QListView::Maximum || myView->columnWidth( i )>0 )
526       myView->setColumnWidthMode( i, mode );
527 }
528 */
529 /*!
530   Updates tree
531   \param obj - start object
532   \param autoOpen - to open automatically branches of autoOpenLevel()
533   \sa autoOpenLevel()
534 */
535 /* TODO: removed
536 void OB_Browser::updateTree( SUIT_DataObject* obj, const bool autoOpen )
537 {
538 //  QTime t1 = QTime::currentTime();
539
540   if ( !obj && !(obj = getRootObject()) )
541     return;
542
543   DataObjectKey curKey;
544   DataObjectMap selObjs, openObjs;
545   DataObjectKeyMap selKeys, openKeys;
546
547   int selNum = numberOfSelected();
548
549   SUIT_DataObject* curObj = storeState( selObjs, openObjs, selKeys, openKeys, curKey );
550
551   updateView( obj );
552
553   restoreState( selObjs, openObjs, curObj, selKeys, openKeys, curKey );
554
555   if ( autoOpen )
556     autoOpenBranches();
557
558   setModified();
559
560   if ( selNum != numberOfSelected() )
561     emit selectionChanged();
562
563 //  QTime t2 = QTime::currentTime();
564 //  qDebug( QString( "update tree time = %1 msecs" ).arg( t1.msecsTo( t2 ) ) );
565 }
566 */
567 /*!
568   Replaces part of tree starting at object 'src' by tree starting at object 'trg'
569 */
570 /* TODO: removed
571 void OB_Browser::replaceTree( SUIT_DataObject* src, SUIT_DataObject* trg )
572 {
573   if ( !src || !trg || src == trg || src->root() != getRootObject() )
574     return;
575
576   DataObjectKey curKey;
577   DataObjectMap selObjs, openObjs;
578   DataObjectKeyMap selKeys, openKeys;
579
580   int selNum = numberOfSelected();
581
582   SUIT_DataObject* curObj = storeState( selObjs, openObjs, selKeys, openKeys, curKey );
583
584   SUIT_DataObject* parent = src->parent();
585   int pos = parent ? parent->childPos( src ) : -1;
586
587   src->setParent( 0 );
588
589   removeConnections( src );
590   if ( isAutoDeleteObjects() )
591     delete src;
592
593   if ( parent && pos != -1 )
594     parent->insertChild( trg, pos );
595
596   trg->setParent( parent );
597
598   updateView( trg );
599   createConnections( trg );
600
601   restoreState( selObjs, openObjs, curObj, selKeys, openKeys, curKey );
602
603   setModified();
604
605   if ( selNum != numberOfSelected() )
606     emit selectionChanged();
607 }
608 */
609 /*!
610   Adjusts width by item
611   \param item
612 */
613 /*
614 void OB_Browser::adjustWidth( QListViewItem* item )
615 {
616   while ( item )
617   {
618     item->widthChanged( 0 );
619     if ( item->isOpen() )
620       adjustWidth( item->firstChild() );
621     item = item->nextSibling();
622   }
623 }
624 */
625
626 /*!
627   \remove all items referencing current (through data objects)
628 */
629 /* TODO:
630 void OB_Browser::removeReferences( QListViewItem* item )
631 {
632   if ( !item )
633     return;
634
635   SUIT_DataObject* obj = dataObject( item );
636   obj->disconnect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
637   myItems.remove( obj );
638
639   QListViewItem* i = item->firstChild();
640   while ( i )
641   {
642     removeReferences( i );
643     i = i->nextSibling();
644   }
645 }
646 */
647 /*!
648   Connects all children to SLOT onDestroyed
649 */
650 /* TODO: move to SUIT_TreeModel
651 void OB_Browser::createConnections( SUIT_DataObject* obj )
652 {
653   if ( !obj )
654     return;
655
656   DataObjectList childList;
657   obj->children( childList, true );
658
659   childList.prepend( obj );
660
661   for ( DataObjectListIterator it( childList ); it.current(); ++it )
662     it.current()->connect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
663 }
664 */
665 /*!
666   Disconnects all children from SLOT onDestroyed
667 */
668 /* TODO: move to SUIT_TreeModel
669 void OB_Browser::removeConnections( SUIT_DataObject* obj )
670 {
671   if ( !obj )
672     return;
673
674   DataObjectList childList;
675   obj->children( childList, true );
676
677   childList.prepend( obj );
678
679   for ( DataObjectListIterator it( childList ); it.current(); ++it )
680     it.current()->disconnect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
681 }
682 */
683 /*!
684   Stores states (opened, selected) of current tree items
685   \return current item
686   \param selObjs, selKeys - maps of selected objects
687   \param openObjs, openKeys - maps of opened objects
688   \param curKey - map of current objects
689 */
690 /* TODO: to be revised
691 SUIT_DataObject* OB_Browser::storeState( DataObjectMap& selObjs, DataObjectMap& openObjs,
692                                          DataObjectKeyMap& selKeys, DataObjectKeyMap& openKeys,
693                                          DataObjectKey& curKey ) const
694 {
695   QListView* lv = listView();
696   if ( !lv )
697     return 0;
698
699   SUIT_DataObject* curObj = dataObject( lv->currentItem() );
700
701   curKey = objectKey( curObj );
702
703   for ( QListViewItemIterator it( lv ); it.current(); ++it )
704   {
705     SUIT_DataObject* obj = dataObject( it.current() );
706     if ( !obj )
707       continue;
708
709     selObjs.insert( obj, lv->isSelected( it.current() ) );
710     openObjs.insert( obj, lv->isOpen( it.current() ) );
711     if ( lv->isSelected( it.current() ) )
712       selKeys.insert( objectKey( obj ), 0 );
713     if ( lv->isOpen( it.current() ) )
714       openKeys.insert( objectKey( obj ), 0 );
715   }
716
717   return curObj;
718 }
719 */
720 /*!
721   Restores states (opened, selected) of current tree items
722   \param selObjs, selKeys - maps of selected objects
723   \param openObjs, openKeys - maps of opened objects
724   \param curKey - map of current objects
725 */
726 /* TODO: to be revised
727 void OB_Browser::restoreState( const DataObjectMap& selObjs, const DataObjectMap& openObjs,
728                                const SUIT_DataObject* curObj, const DataObjectKeyMap& selKeys,
729                                const DataObjectKeyMap& openKeys, const DataObjectKey& curKey )
730 {
731   QListView* lv = listView();
732   if ( !lv )
733     return;
734
735   bool block = lv->signalsBlocked();
736   lv->blockSignals( true );
737
738   QListViewItem* curItem = 0;
739   for ( QListViewItemIterator it( lv ); it.current(); ++it )
740   {
741     QListViewItem* item = it.current();
742     SUIT_DataObject* obj = dataObject( item );
743
744     if ( !obj )
745       continue;
746
747     DataObjectKey key = objectKey( obj );
748
749     if ( selObjs.contains( obj ) )
750     {
751       if ( selObjs[obj] && !lv->isSelected( item ) )
752         lv->setSelected( item, true );
753     }
754     else if ( !key.isNull() && selKeys.contains( key ) && !lv->isSelected( item ) )
755       lv->setSelected( item, true );
756
757     if ( openObjs.contains( obj ) )
758     {
759       bool parentOpen = true;
760       if( item && item->parent() )
761         parentOpen = item->parent()->isOpen();
762
763       if ( openObjs[obj] && parentOpen )
764         lv->setOpen( item, true );
765     }
766     else if ( !key.isNull() && openKeys.contains( key ) )
767     {
768       bool parentOpen = true;
769       if( item && item->parent() )
770         parentOpen = item->parent()->isOpen();
771
772       if( parentOpen )
773         lv->setOpen( item, true );
774     }
775
776     if ( !curItem && ( curObj == obj || ( !curKey.isNull() && curKey == key )) )
777       curItem = item;
778   }
779
780   if ( curItem )
781     lv->setCurrentItem( curItem );
782
783   lv->blockSignals( block );
784 }
785 */
786 /*!
787   Creates object key by tree item
788 */
789 /* TODO: move to SUIT_TreeModel
790 OB_Browser::DataObjectKey OB_Browser::objectKey( QListViewItem* i ) const
791 {
792   return objectKey( dataObject( i ) );
793 }
794 */
795 /*!
796   Creates object key by SUIT object
797 */
798 /* TODO: move to SUIT_TreeModel
799 OB_Browser::DataObjectKey OB_Browser::objectKey( SUIT_DataObject* obj ) const
800 {
801   if ( !obj )
802     return 0;
803
804   return DataObjectKey( obj->key() );
805 }
806 */
807
808 /*!
809   \brief Get tree view widget.
810   \return tree view widget of the object browser
811 */
812 QtxTreeView* OB_Browser::treeView() const
813 {
814   return myView;
815 }
816
817 /*!
818   \brief Process context menu request event.
819   \param e context menu event
820 */
821 void OB_Browser::contextMenuEvent( QContextMenuEvent* e )
822 {
823   QMenu* popup = new QMenu();
824   
825   createPopupMenu( popup );
826
827   Qtx::simplifySeparators( popup );
828
829   if ( !popup->actions().isEmpty() )
830     popup->exec( e->globalPos() );
831   delete popup;
832 }
833
834 /*!
835   \brief Get the time of the latest updating.
836   \return latest updating time
837 */
838 unsigned long OB_Browser::getModifiedTime() const
839
840   return myModifiedTime; 
841 }
842
843 /*!
844   \brief Update the time of the latest updating.
845 */
846 void OB_Browser::setModified()
847 {
848   myModifiedTime = clock();
849 }
850
851 /*!
852   \brief Called when "Expand all" popup menu command is activated.
853   
854   Expands all selected items recursively.
855 */
856 void OB_Browser::onExpandAll()
857 {
858   QModelIndexList indexes = selectedIndexes();
859   QModelIndex index;
860
861   foreach ( index, indexes ) {
862     myView->expandAll( index );
863   }
864 }
865
866 /*!
867   \brief Called when "Collapse all" popup menu command is activated.
868   
869   Collapse all selected items recursively.
870 */
871 void OB_Browser::onCollapseAll()
872 {
873   QModelIndexList indexes = selectedIndexes();
874   QModelIndex index;
875
876   foreach ( index, indexes ) {
877     myView->collapseAll( index );
878   }
879 }
880
881 /*!
882   SLOT: called if SUIT object is destroyed
883 */
884 /* TODO: moved to SUIT_TreeModel
885 void OB_Browser::onDestroyed( SUIT_DataObject* obj )
886 {
887   removeObject( obj );
888 }
889 */
890 /*!
891   SLOT: called on finish of drag-n-drop operation
892   \param items - dragged items
893   \param item - destination (item on that they were dropped)
894   \param action - QDropEvent::Action
895 */
896   // TODO: drag-n-drop works differently - SUIT_TreeModel to be updated
897   // and QTreeView needs some setup
898 /*
899 void OB_Browser::onDropped( QPtrList<QListViewItem> items, QListViewItem* item, int action )
900 {
901   SUIT_DataObject* obj = dataObject( item );
902   if ( !obj )
903     return;
904
905   DataObjectList lst;
906   for ( QPtrListIterator<QListViewItem> it( items ); it.current(); ++it )
907   {
908     SUIT_DataObject* o = dataObject( it.current() );
909     if ( o )
910       lst.append( o );
911   }
912
913   if ( !lst.isEmpty() )
914     emit dropped( lst, obj, action );
915 }
916 */
917 /*!
918   Updates texts of items
919 */
920 /* TODO: to be removed
921 void OB_Browser::updateText()
922 {
923   if ( myColumnIds.isEmpty() )
924     return;
925
926   QListView* lv = listView();
927   if ( !lv )
928     return;
929
930   for ( QListViewItemIterator it( lv ); it.current(); ++it )
931   {
932     SUIT_DataObject* obj = dataObject( it.current() );
933     if ( !obj )
934       continue;
935
936     for( QMap<int, int>::iterator itr = myColumnIds.begin(); itr != myColumnIds.end(); ++itr )
937       it.current()->setText( itr.data(), obj->text( itr.key() ) );
938   }
939 }
940 */
941 /*!
942   \return true if item must be updated
943   \param item - item to be checked
944 */
945 /* TODO: to be revised
946 bool OB_Browser::needToUpdateTexts( QListViewItem* item ) const
947 {
948   SUIT_DataObject* obj = dataObject( item );
949   if ( !obj )
950     return false;
951
952   for( QMap<int, int>::const_iterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
953     if( item->text( it.data() ) != obj->text( it.key() ) )
954       return true;
955   return false;
956 }
957 */
958 /*!
959   Updates texts of item
960   \param item - item to be updated
961 */
962 /* TODO: to be revised
963 void OB_Browser::updateText( QListViewItem* item )
964 {
965   SUIT_DataObject* obj = dataObject( item );
966   if ( !obj )
967     return;
968
969   for( QMap<int, int>::iterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
970     item->setText( it.data(), obj->text( it.key() ) );
971 }
972 */
973
974 /*!
975   \brief Add custom actions to the popup menu.
976   \param menu popup menu
977 */
978 void OB_Browser::createPopupMenu( QMenu* menu )
979 {
980   menu->addSeparator();
981
982   QModelIndexList indexes = selectedIndexes();
983
984   bool closed = false, opened = false;
985   
986   for ( QModelIndexList::Iterator it = indexes.begin(); 
987         it != indexes.end() && !closed; ++it ) {
988     closed = hasCollased( *it );
989   }
990
991   for ( QModelIndexList::Iterator it = indexes.begin(); 
992         it != indexes.end() && !opened; ++it ) {
993     opened = hasExpanded( *it );
994   }
995
996   if ( closed )
997     menu->addAction( tr( "MEN_EXPAND_ALL" ), this, SLOT( onExpandAll() ) );
998   if ( opened )
999     menu->addAction( tr( "MEN_COLLAPSE_ALL" ), this, SLOT( onCollapseAll() ) );
1000
1001   if ( isSearchToolEnabled() ) {
1002     menu->addSeparator();
1003     menu->addAction( tr( "MEN_FIND" ), searchTool(), SLOT( find() ), QKeySequence(Qt::CTRL + Qt::Key_F) );
1004     menu->addSeparator();
1005   }
1006 }
1007
1008 /*!
1009   Expands item with all it's children
1010 */
1011 /* TODO: to be revised
1012 void OB_Browser::expand( QListViewItem* item )
1013 {
1014   if ( !item )
1015     return;
1016
1017   item->setOpen( true );
1018   for ( QListViewItem* child = item->firstChild(); child; child = child->nextSibling() )
1019     expand( child );
1020 }
1021 */
1022 /*!
1023   \brief Check if model index is collapsed or has collapsed children.
1024   \return \c true if item or one of its children is collapsed
1025 */
1026 bool OB_Browser::hasCollased( const QModelIndex& index ) const
1027 {
1028   bool result = false;
1029
1030   if ( index.isValid() && model() ) {
1031     bool hasChildren = model()->hasChildren( index );
1032     result = hasChildren && !myView->isExpanded( index );
1033     if ( !result && hasChildren ) {
1034       int rows = model()->rowCount( index );
1035       for ( int i = 0; i < rows && !result; i ++ ) {
1036         QModelIndex child = model()->index( i, 0, index );
1037         result = hasCollased( child );
1038       }
1039     }
1040   }
1041   return result;
1042 }
1043
1044 /*!
1045   \brief Check if model index is expanded or has expanded children.
1046   \return \c true if item or one of its children is expanded
1047 */
1048 bool OB_Browser::hasExpanded( const QModelIndex& index ) const
1049 {
1050   bool result = false;
1051
1052   if ( index.isValid() && model() ) {
1053     bool hasChildren = model()->hasChildren( index );
1054     result = hasChildren && myView->isExpanded( index );
1055     if ( !result && hasChildren ) {
1056       int rows = model()->rowCount( index );
1057       for ( int i = 0; i < rows && !result; i ++ ) {
1058         QModelIndex child = model()->index( i, 0, index );
1059         result = hasExpanded( child );
1060       }
1061     }
1062   }
1063   return result;
1064 }
1065
1066 /*!
1067   Removes SUIT object
1068   \param obj - SUIT object to be removed
1069   \param autoUpd - auto tree updating
1070 */
1071 /* TODO: moved to SUIT_TreeModel
1072 void OB_Browser::removeObject( SUIT_DataObject* obj, const bool autoUpd )
1073 {
1074   if ( !obj )
1075     return;
1076
1077   // Removing list view items from <myItems> recursively for all children.
1078   // Otherwise, "delete item" line will destroy all item's children,
1079   // and <myItems> will contain invalid pointers (see ~QListViewItem() description in Qt docs)
1080   DataObjectList childList;
1081   obj->children( childList, true );
1082   for ( DataObjectListIterator it( childList ); it.current(); ++it )
1083   {
1084     it.current()->disconnect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
1085     myItems.remove( it.current() );
1086   }
1087
1088   QListViewItem* item = listViewItem( obj );
1089
1090   obj->disconnect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
1091   myItems.remove( obj );
1092
1093   if ( obj == myRoot )
1094   {
1095     // remove all child list view items
1096     setRootObject( 0 );
1097     return;
1098   }
1099
1100   if( !autoUpd )
1101     return;
1102
1103   if ( isAutoUpdate() )
1104   {
1105     SUIT_DataObject* pObj = item && item->parent() ? dataObject( item->parent() ) : 0;
1106     updateTree( pObj, false );
1107   }
1108
1109   delete item;
1110 }
1111 */
1112 /*!
1113   Opens branches from 1 to autoOpenLevel()
1114   \sa autoOpenLevel()
1115 */
1116 /* TODO: to be revised
1117 void OB_Browser::autoOpenBranches()
1118 {
1119   openLevels();
1120 }
1121 */
1122 /*!
1123   Opens branch
1124   \param item
1125   \param level
1126 */
1127 /* TODO: to be revised
1128 void OB_Browser::openBranch( QListViewItem* item, const int level )
1129 {
1130   if ( level < 1 )
1131     return;
1132
1133   while ( item )
1134   {
1135     item->setOpen( true );
1136     openBranch( item->firstChild(), level - 1 );
1137     item = item->nextSibling();
1138   }
1139 }
1140 */
1141 /*!
1142   SLOT: called on double click on item, emits signal
1143 */
1144 /* TODO: to be revised
1145 void OB_Browser::onDoubleClicked( QListViewItem* item )
1146 {
1147   if ( item )
1148     emit doubleClicked( dataObject( item ) );
1149 }
1150 */
1151
1152 /*!
1153   \fn void OB_Browser::selectionChanged();
1154   \brief Emitted when selection is changed in the Object Browser.
1155 */