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