Salome HOME
cfac7369726439136ef2b0173f1906b4f130a6bb
[modules/gui.git] / src / ObjBrowser / OB_Browser.cxx
1 #include "OB_Browser.h"
2
3 #include "OB_Filter.h"
4 #include "OB_ListItem.h"
5 #include "OB_ListView.h"
6
7 #include <qcursor.h>
8 #include <qlayout.h>
9 #include <qtooltip.h>
10 #include <qpainter.h>
11 #include <qwmatrix.h>
12 #include <qlistview.h>
13 #include <qpopupmenu.h>
14
15 /*!
16     Class: OB_Browser::ToolTip
17     Descr: Tool tip for OB_Browser.
18 */
19
20 class OB_Browser::ToolTip : public QToolTip
21 {
22 public:
23   ToolTip( OB_Browser* b, QWidget* p = 0 );
24   virtual ~ToolTip();
25
26   void        maybeTip( const QPoint& );
27
28 private:
29   OB_Browser* myBrowser;
30 };
31
32 OB_Browser::ToolTip::ToolTip( OB_Browser* b, QWidget* p )
33 : QToolTip( p ),
34 myBrowser( b )
35 {
36 }
37
38 OB_Browser::ToolTip::~ToolTip()
39 {
40 }
41
42 void OB_Browser::ToolTip::maybeTip( const QPoint& pos )
43 {
44   if ( !parentWidget() || !myBrowser || !myBrowser->isShowToolTips() )
45           return;
46
47   QListView* lv = myBrowser->getListView();
48
49   QListViewItem* item = lv->itemAt( pos );
50   SUIT_DataObject* obj = myBrowser->dataObject( item );
51   if ( !obj )
52     return;
53
54   QString aText = obj->toolTip();
55
56   if ( aText.isEmpty() )
57     return;
58
59   QRect aRect = lv->itemRect( item );
60
61   tip( aRect, aText );
62 }
63
64 /*!
65     Class: OB_Browser
66     Descr: Hierarchical tree object browser.
67 */
68
69 OB_Browser::OB_Browser( QWidget* parent, SUIT_DataObject* root )
70 : QFrame( parent ),
71
72 myRoot( 0 ),
73 myTooltip( 0 ),
74 myAutoOpenLevel( 0 ),
75 myAutoUpdate( false ),
76 myAutoDelObjs( false ),
77 myRootDecorated( true )
78 {
79   myView = new OB_ListView( this );
80   myView->addColumn( "Data" );
81   myView->setSorting( -1 );
82   myView->setRootIsDecorated( true );
83   myView->setSelectionMode( QListView::Extended );
84   myView->installEventFilter( this );
85
86   QVBoxLayout* main = new QVBoxLayout( this );
87   main->addWidget( myView );
88
89   myShowToolTips = true;
90   myTooltip = new ToolTip( this, myView->viewport() );
91
92   connect( myView, SIGNAL( dropped( QPtrList<QListViewItem>, QListViewItem*, int ) ),
93            this, SLOT( onDropped( QPtrList<QListViewItem>, QListViewItem*, int ) ) );
94   connect( myView, SIGNAL( selectionChanged() ), this, SIGNAL( selectionChanged() ) );
95
96   setRootObject( root );
97 }
98
99 OB_Browser::~OB_Browser()
100 {
101   myItems.clear();
102   delete myTooltip;
103 }
104
105 bool OB_Browser::rootIsDecorated() const
106 {
107   return myRootDecorated;
108 }
109
110 void OB_Browser::setRootIsDecorated( const bool decor )
111 {
112   if ( decor == rootIsDecorated() ) 
113     return;
114
115   myRootDecorated = decor;
116   updateTree();
117 }
118
119 int OB_Browser::autoOpenLevel() const
120 {
121   return myAutoOpenLevel;
122 }
123
124 void OB_Browser::setAutoOpenLevel( const int level )
125 {
126   if ( myAutoOpenLevel == level )
127     return;
128
129   myAutoOpenLevel = level;
130
131   autoOpenBranches();
132 }
133
134 bool OB_Browser::isShowToolTips()
135 {
136   return myShowToolTips;
137 }
138
139 void OB_Browser::setShowToolTips( const bool theDisplay )
140 {
141   myShowToolTips = theDisplay;
142 }
143
144 bool OB_Browser::isAutoUpdate() const
145 {
146   return myAutoUpdate;
147 }
148
149 void OB_Browser::setAutoUpdate( const bool on )
150 {
151   myAutoUpdate = on;
152 }
153
154 bool OB_Browser::isAutoDeleteObjects() const
155 {
156   return myAutoDelObjs;
157 }
158
159 void OB_Browser::setAutoDeleteObjects( const bool on )
160 {
161   myAutoDelObjs = on;
162 }
163
164 SUIT_DataObject* OB_Browser::getRootObject() const
165 {
166   return myRoot;
167 }
168
169 void OB_Browser::setRootObject( SUIT_DataObject* theRoot )
170 {
171   DataObjectKey curKey;
172   DataObjectMap selObjs, openObjs;
173   DataObjectKeyMap selKeys, openKeys;
174
175   int selNum = numberOfSelected();
176
177   SUIT_DataObject* curObj = 0;
178   if ( theRoot )
179     curObj = storeState( selObjs, openObjs, selKeys, openKeys, curKey );
180
181   if ( myRoot != theRoot && isAutoDeleteObjects() )
182     delete myRoot;
183
184   myRoot = theRoot;
185
186   createConnections( myRoot );
187
188   if ( myRoot )
189     updateView( myRoot );
190   else if ( getListView() )
191   {
192     myItems.clear();
193     getListView()->clear();
194   }
195
196   restoreState( selObjs, openObjs, curObj, selKeys, openKeys, curKey );
197
198   autoOpenBranches();
199
200   if ( selNum != numberOfSelected() )
201     emit selectionChanged();
202 }
203
204 int OB_Browser::numberOfSelected() const
205 {
206   int count = 0;
207   if ( getListView() )
208   {
209     for ( QListViewItemIterator it( getListView() ); it.current(); ++it )
210       if ( it.current()->isSelected() ) 
211         count++;
212   }
213   return count;
214 }
215
216 DataObjectList OB_Browser::getSelected() const
217 {
218   DataObjectList lst;
219   getSelected( lst );
220   return lst;
221 }
222
223 void OB_Browser::getSelected( DataObjectList& theObjList ) const
224 {
225   theObjList.clear();
226
227   if ( !getListView() )
228     return;
229
230   for ( QListViewItemIterator it( getListView() ); it.current(); ++it )
231   {
232     if ( it.current()->isSelected() ) 
233     {
234       SUIT_DataObject* obj = dataObject( it.current() );
235       if ( obj )
236               theObjList.append( obj );
237     }
238   }
239 }
240
241 void OB_Browser::setSelected( const SUIT_DataObject* theObject, const bool append )
242 {
243   DataObjectList lst;
244   lst.append( theObject );
245   setSelected( lst, append );
246 }
247
248 void OB_Browser::setSelected( const DataObjectList& theObjLst, const bool append )
249 {
250   QListView* lv = getListView();
251
252   if ( !lv )
253     return;
254
255   bool changed = false;
256   bool block = lv->signalsBlocked();
257   lv->blockSignals( true );
258
259   QMap<QListViewItem*, int> map;
260   for ( DataObjectListIterator itr( theObjLst ); itr.current(); ++itr )
261     map.insert( listViewItem( itr.current() ), 0 );
262
263   for ( QListViewItemIterator it( lv ); it.current(); ++it )
264   {
265     QListViewItem* item = it.current();
266     if ( map.contains( item ) && !lv->isSelected( item ) )
267     {
268       changed = true;
269       lv->setSelected( item, true );
270     }
271     if ( !append && !map.contains( item ) && lv->isSelected( item ) )
272     {
273       changed = true;
274       lv->setSelected( item, false );
275     }
276   }
277
278   lv->blockSignals( block );
279
280   if ( changed )
281   {
282     int count = 0;
283     QListViewItem* sel = 0;
284     QListViewItem* cur = lv->currentItem();
285     for ( QListViewItemIterator iter( lv ); iter.current() && !sel; ++iter, count++ )
286     {
287       if ( iter.current()->isSelected() && cur == iter.current() )
288         sel = iter.current();
289     }
290
291     for ( QListViewItemIterator itr( lv ); itr.current() && !sel; ++itr )
292     {
293       if ( itr.current()->isSelected() )
294               sel = itr.current();
295     }
296
297     if ( sel )
298       lv->setCurrentItem( sel );
299
300     if ( sel && count == 1 )
301       lv->ensureItemVisible( sel );
302
303     emit selectionChanged();
304   }
305 }
306
307 bool OB_Browser::isOpen( SUIT_DataObject* theObject ) const
308 {
309   bool res = false;
310   if ( getListView() )
311     res = getListView()->isOpen( listViewItem( theObject ) );
312   return res;
313 }
314
315 void OB_Browser::setOpen( SUIT_DataObject* theObject, const bool theOpen )
316 {
317   if ( getListView() )
318     getListView()->setOpen( listViewItem( theObject ), theOpen );
319 }
320
321 SUIT_DataObject* OB_Browser::dataObjectAt( const QPoint& pos ) const
322 {
323   SUIT_DataObject* obj = 0;
324
325   QListView* lv = getListView();
326   if ( lv )
327     obj = dataObject( lv->itemAt( pos ) );
328
329   return obj;
330 }
331
332 OB_Filter* OB_Browser::filter() const
333 {
334   return myView->filter();
335 }
336
337 void OB_Browser::setFilter( OB_Filter* f )
338 {
339   myView->setFilter( f );
340 }
341
342 int OB_Browser::addColumn( const QString & label, int width, int index )
343 {
344   int id = -1;
345   if ( !myView )
346     return id;
347   if ( index != -1 && myColumnIds.contains( index ) )
348     return id; // can not reuse index
349
350   int trueId = index;
351   id = myView->addColumn( label, width );
352   if ( trueId == -1 )
353     trueId = id;
354   myColumnIds.insert( trueId, id );
355   updateText();
356
357   return trueId;
358 }
359
360 int OB_Browser::addColumn( const QIconSet & iconset, const QString & label, int width, int index )
361 {
362   int id = -1;
363   if ( !myView )
364     return id;
365   if ( index != -1 && myColumnIds.contains( index ) )
366     return id; // can not reuse index
367
368   int trueId = index;
369   id = myView->addColumn( iconset, label, width );
370   if ( trueId == -1 )
371     trueId = id;
372   myColumnIds.insert( trueId, id );
373   updateText();
374
375   return trueId;
376 }
377
378 void OB_Browser::removeColumn( int index )
379 {
380   if ( !myView || !myColumnIds.contains( index ) )
381     return;
382
383   int id = myColumnIds[ index ];
384   myView->removeColumn( id );
385
386   // update map of column indeces
387   myColumnIds.remove( index );
388   for ( QMap<int, int>::iterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
389   {
390     if ( it.key() > index )
391       it.data()--;
392   }
393   updateText();
394 }
395
396 void OB_Browser::updateTree( SUIT_DataObject* o )
397 {
398   SUIT_DataObject* obj = o ? o : getRootObject();
399   if ( !obj )
400     return;
401
402   DataObjectKey curKey;
403   DataObjectMap selObjs, openObjs;
404   DataObjectKeyMap selKeys, openKeys;
405
406   int selNum = numberOfSelected();
407
408   SUIT_DataObject* curObj = storeState( selObjs, openObjs, selKeys, openKeys, curKey );
409
410   createConnections( obj );
411   updateView( obj );
412
413   restoreState( selObjs, openObjs, curObj, selKeys, openKeys, curKey );
414
415   autoOpenBranches();
416
417   if ( selNum != numberOfSelected() )
418     emit selectionChanged();
419 }
420
421 void OB_Browser::replaceTree( SUIT_DataObject* src, SUIT_DataObject* trg )
422 {
423   if ( !src || !trg || src->root() != getRootObject() )
424     return;
425
426   DataObjectKey curKey;
427   DataObjectMap selObjs, openObjs;
428   DataObjectKeyMap selKeys, openKeys;
429
430   int selNum = numberOfSelected();
431
432   SUIT_DataObject* curObj = storeState( selObjs, openObjs, selKeys, openKeys, curKey );
433
434   SUIT_DataObject* parent = src->parent();
435   int pos = parent ? parent->childPos( src ) : -1;
436
437   src->setParent( 0 );
438
439   if ( src != trg && isAutoDeleteObjects() )
440     delete src;
441
442   if ( parent && pos != -1 )
443     parent->insertChild( trg, pos );
444
445   trg->setParent( parent );
446
447   createConnections( trg );
448   updateView( trg );
449
450   restoreState( selObjs, openObjs, curObj, selKeys, openKeys, curKey );
451
452   autoOpenBranches();
453
454   if ( selNum != numberOfSelected() )
455     emit selectionChanged();
456 }
457
458 void OB_Browser::updateView( const SUIT_DataObject* theStartObj )
459 {
460   QListView* lv = getListView();
461   if ( !lv )
462     return;
463
464   if ( !theStartObj || theStartObj->root() != getRootObject() )
465     return;
466
467   QListViewItem* after = 0;
468   QListViewItem* parent = 0;
469   QListViewItem* startItem = listViewItem( theStartObj );
470
471   if ( theStartObj->parent() )
472     parent = listViewItem( theStartObj->parent() );
473
474   QListViewItem* prv = 0;
475   QListViewItem* cur = parent ? parent->firstChild() : lv->firstChild();
476   while ( !after && cur )
477   {
478     if ( cur == startItem )
479       after = prv;
480
481     prv = cur;
482     cur = cur->nextSibling();
483   }
484
485   QPtrList<QListViewItem> delList;
486   if ( !startItem && theStartObj == getRootObject() )
487   {
488     for ( QListViewItem* item = lv->firstChild(); item; item = item->nextSibling() )
489       delList.append( item );
490   }
491   else
492     delList.append( startItem );
493
494   for ( QPtrListIterator<QListViewItem> it( delList ); it.current(); ++it )
495   {
496     removeReferences( it.current() );
497     delete it.current();
498   }
499
500   // for myRoot object, if myShowRoot==false, then creating multiple top-level QListViewItem-s
501   // (which will correspond to myRoot's children = Modules).  
502   if ( rootIsDecorated() && theStartObj == myRoot )
503   {
504     DataObjectList lst;
505     theStartObj->children( lst );
506     DataObjectListIterator it ( lst );
507     // iterating backward to preserve the order of elements in the tree
508     for ( it.toLast(); it.current(); --it )
509       createTree( it.current(), 0, 0 );
510   }
511   else
512     createTree( theStartObj, parent, after );
513 }
514
515 QListViewItem* OB_Browser::createTree( const SUIT_DataObject* obj,
516                                           QListViewItem* parent, QListViewItem* after )
517 {
518   if ( !obj )
519     return 0;
520   
521   QListViewItem* item = createItem( obj, parent, after );
522
523   DataObjectList lst;
524   obj->children( lst );
525   for ( DataObjectListIterator it ( lst ); it.current(); ++it )
526     createTree( it.current(), item );
527
528   return item;
529 }
530
531 QListViewItem* OB_Browser::createItem( const SUIT_DataObject* o,
532                                        QListViewItem* parent, QListViewItem* after )
533 {
534   QListView* lv = getListView();
535
536   if ( !lv || !o )
537     return 0;
538
539   QListViewItem* item = 0;
540   SUIT_DataObject* obj = (SUIT_DataObject*)o;
541
542   int type = -1;
543
544   switch ( obj->checkType() )
545   {
546   case SUIT_DataObject::CheckBox:
547     type = QCheckListItem::CheckBox;
548     break;
549   case SUIT_DataObject::RadioButton:
550     type = QCheckListItem::RadioButton;
551     break;
552   }
553
554   if ( parent )
555   {
556     if ( parent->childCount() && !after )
557     {
558       after = parent->firstChild();
559       while ( after->nextSibling() )
560         after = after->nextSibling();
561     }
562
563     if ( after )
564     {
565       if ( type == -1 )
566         item = new OB_ListItem( obj, parent, after );
567       else
568         item = new OB_CheckListItem( obj, parent, after, (QCheckListItem::Type)type );
569     }
570     else
571     {
572       if ( type == -1 )
573         item = new OB_ListItem( obj, parent );
574       else
575         item = new OB_CheckListItem( obj, parent,  (QCheckListItem::Type)type );
576     }
577   }
578   else // ROOT item
579   {
580     if ( type == -1 )
581       item = new OB_ListItem( obj, lv );
582     else
583       item = new OB_CheckListItem( obj, lv,  (QCheckListItem::Type)type );
584   }
585
586   myItems.insert( obj, item );
587
588   return item;
589 }
590
591 void OB_Browser::adjustWidth()
592 {
593   if ( !getListView() )
594     return;
595
596   getListView()->setColumnWidth( 0, 0 );
597   if ( getListView()->firstChild() )
598     adjustWidth( getListView()->firstChild() );
599 }
600
601 void OB_Browser::adjustWidth( QListViewItem* item )
602 {
603   while ( item )
604   {
605     item->widthChanged( 0 );
606     if ( item->isOpen() )
607       adjustWidth( item->firstChild() );
608     item = item->nextSibling();
609   }
610 }
611
612 SUIT_DataObject* OB_Browser::dataObject( const QListViewItem* item ) const
613 {
614   SUIT_DataObject* obj = 0;
615
616   if ( item && item->rtti() == OB_ListItem::RTTI() )
617     obj = ((OB_ListItem*)item)->dataObject();
618   else if ( item && item->rtti() == OB_CheckListItem::RTTI() )
619     obj = ((OB_CheckListItem*)item)->dataObject();
620
621   return obj;
622 }
623
624 QListViewItem* OB_Browser::listViewItem( const SUIT_DataObject* obj ) const
625 {
626   QListViewItem* item = 0;
627
628   if ( myItems.contains( (SUIT_DataObject*)obj ) )
629     item = myItems[(SUIT_DataObject*)obj];
630
631   return item;
632 }
633
634 QListView* OB_Browser::getListView() const
635 {
636   return myView;
637 }
638
639 void OB_Browser::removeReferences( QListViewItem* item )
640 {
641   if ( !item )
642     return;
643
644   SUIT_DataObject* obj = dataObject( item );
645   myItems.remove( obj );
646
647   QListViewItem* i = item->firstChild();
648   while ( i )
649   {
650     removeReferences( i );
651     i = i->nextSibling();
652   }
653 }
654
655 void OB_Browser::createConnections( SUIT_DataObject* obj )
656 {
657   if ( !obj )
658     return;
659
660   DataObjectList childList;
661   obj->children( childList, true );
662
663   childList.prepend( obj );
664
665   for ( DataObjectListIterator it( childList ); it.current(); ++it )
666     it.current()->connect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
667 }
668
669 SUIT_DataObject* OB_Browser::storeState( DataObjectMap& selObjs, DataObjectMap& openObjs,
670                                          DataObjectKeyMap& selKeys, DataObjectKeyMap& openKeys,
671                                          DataObjectKey& curKey ) const
672 {
673   QListView* lv = getListView();
674   if ( !lv )
675     return 0;
676
677   SUIT_DataObject* curObj = dataObject( lv->currentItem() );
678
679   curKey = objectKey( curObj );
680
681   for ( QListViewItemIterator it( lv ); it.current(); ++it )
682   {
683     SUIT_DataObject* obj = dataObject( it.current() );
684     if ( !obj )
685       continue;
686
687     selObjs.insert( obj, lv->isSelected( it.current() ) );
688     openObjs.insert( obj, lv->isOpen( it.current() ) );
689     if ( lv->isSelected( it.current() ) )
690       selKeys.insert( objectKey( obj ), 0 );
691     if ( lv->isOpen( it.current() ) )
692       openKeys.insert( objectKey( obj ), 0 );
693   }
694
695   return curObj;
696 }
697
698 void OB_Browser::restoreState( const DataObjectMap& selObjs, const DataObjectMap& openObjs,
699                                const SUIT_DataObject* curObj, const DataObjectKeyMap& selKeys,
700                                const DataObjectKeyMap& openKeys, const DataObjectKey& curKey )
701 {
702   QListView* lv = getListView();
703   if ( !lv )
704     return;
705
706   bool block = lv->signalsBlocked();
707   lv->blockSignals( true );
708
709   QListViewItem* curItem = 0;
710   for ( QListViewItemIterator it( lv ); it.current(); ++it )
711   {
712     QListViewItem* item = it.current();
713     SUIT_DataObject* obj = dataObject( item );
714
715     if ( !obj )
716       continue;
717
718     DataObjectKey key = objectKey( obj );
719
720     if ( selObjs.contains( obj ) )
721     {
722       if ( selObjs[obj] && !lv->isSelected( item ) )
723         lv->setSelected( item, true );
724     }
725     else if ( !key.isNull() && selKeys.contains( key ) && !lv->isSelected( item ) )
726       lv->setSelected( item, true );
727
728     if ( openObjs.contains( obj ) )
729     {
730       if ( openObjs[obj] )
731         lv->setOpen( item, true );
732     }
733     else if ( !key.isNull() && openKeys.contains( key ) )
734       lv->setOpen( item, true );
735
736     if ( !curItem && ( curObj == obj || ( !curKey.isNull() && curKey == key )) )
737       curItem = item;
738   }
739
740   if ( curItem )
741     lv->setCurrentItem( curItem );
742
743   lv->blockSignals( block );
744 }
745
746 OB_Browser::DataObjectKey OB_Browser::objectKey( QListViewItem* i ) const
747 {
748   return objectKey( dataObject( i ) );
749 }
750
751 OB_Browser::DataObjectKey OB_Browser::objectKey( SUIT_DataObject* obj ) const
752 {
753   if ( !obj )
754     return 0;
755
756   return DataObjectKey( obj->key() );
757 }
758
759 void OB_Browser::keyPressEvent( QKeyEvent* e )
760 {
761   if ( e->key() == Qt::Key_F5 )
762     updateTree();
763
764   QFrame::keyPressEvent( e );
765 }
766
767 void OB_Browser::onExpand()
768 {
769   DataObjectList selected;
770   getSelected( selected );
771   for ( DataObjectListIterator itr( selected ); itr.current(); ++itr )
772     expand( listViewItem( itr.current() ) );
773 }
774
775 void OB_Browser::onRefresh()
776 {
777   updateTree();
778 }
779
780 void OB_Browser::onDestroyed( SUIT_DataObject* obj )
781 {
782   removeObject( obj );
783 }
784
785 void OB_Browser::onDropped( QPtrList<QListViewItem> items, QListViewItem* item, int action )
786 {
787   SUIT_DataObject* obj = dataObject( item );
788   if ( !obj )
789     return;
790
791   DataObjectList lst;
792   for ( QPtrListIterator<QListViewItem> it( items ); it.current(); ++it )
793   {
794     SUIT_DataObject* o = dataObject( it.current() );
795     if ( o )
796       lst.append( o );
797   }
798
799   if ( !lst.isEmpty() )
800     emit dropped( lst, obj, action );
801 }
802
803 void OB_Browser::updateText()
804 {
805   if ( !myView )
806     return;
807   
808   if ( myColumnIds.size() )
809   {
810     QListViewItemIterator it( myView );
811     for ( ; it.current() != 0; ++it )
812     {
813       QListViewItem* item = it.current();
814       SUIT_DataObject* obj = dataObject( item );
815       if ( !item || !obj )
816         continue;
817       QMap<int, int>::iterator it = myColumnIds.begin();
818       for( ; it != myColumnIds.end(); ++it )
819         item->setText( it.data(), obj->text( it.key() ) );
820     }
821   }
822   updateView();
823 }
824
825 bool OB_Browser::eventFilter(QObject* watched, QEvent* e)
826 {
827   if ( watched == myView && e->type() == QEvent::ContextMenu )
828   {
829     contextMenuRequest( (QContextMenuEvent*)e );
830     return true;
831   }
832   return QFrame::eventFilter(watched, e);
833 }
834
835 void OB_Browser::contextMenuPopup( QPopupMenu* menu )
836 {
837   DataObjectList selected;
838   getSelected( selected );
839
840   bool closed = false;
841   for ( DataObjectListIterator itr( selected ); itr.current() && !closed; ++itr )
842     closed = hasClosed( listViewItem( itr.current() ) );
843
844   if ( closed )
845   {
846     menu->insertItem( tr( "MEN_EXPAND_ALL" ), this, SLOT( onExpand() ) );
847     menu->insertSeparator();
848   }
849   menu->insertItem( tr( "MEN_REFRESH" ), this, SLOT( onRefresh() ) );
850 }
851
852 void OB_Browser::expand( QListViewItem* item )
853 {
854   if ( !item )
855     return;
856
857   item->setOpen( true );
858   for ( QListViewItem* child = item->firstChild(); child; child = child->nextSibling() )
859     expand( child );
860 }
861
862 bool OB_Browser::hasClosed( QListViewItem* item ) const
863 {
864   if ( !item )
865     return false;
866
867   if ( item->childCount() && !item->isOpen() )
868     return true;
869
870   bool has = false;
871   for ( QListViewItem* child = item->firstChild(); child && !has; child = child->nextSibling() )
872     has = hasClosed( child );
873
874   return has;
875 }
876
877 void OB_Browser::removeObject( SUIT_DataObject* obj, const bool autoUpd )
878 {
879   if ( !obj )
880     return;
881
882   // Removing list view items from <myItems> recursively for all children.
883   // Otherwise, "delete item" line will destroy all item's children,
884   // and <myItems> will contain invalid pointers (see ~QListViewItem() description in Qt docs)
885   DataObjectList childList;
886   obj->children( childList );
887   for ( DataObjectListIterator it( childList ); it.current(); ++it )
888     removeObject( it.current(), false );
889
890   QListViewItem* item = listViewItem( obj );
891
892   myItems.remove( obj );
893
894   if ( obj == myRoot )
895     myRoot = 0;
896
897   if ( !autoUpd )
898     return;
899
900   if ( isAutoUpdate() )
901   {
902     SUIT_DataObject* pObj = item && item->parent() ? dataObject( item->parent() ) : 0;
903     updateTree( pObj );
904   }
905   else
906     delete item;
907 }
908
909 void OB_Browser::autoOpenBranches()
910 {
911   int level = autoOpenLevel();
912   QListView* lv = getListView();
913   if ( !lv || level < 1 )
914     return;
915
916   QListViewItem* item = lv->firstChild();
917   while ( item )
918   {
919     openBranch( item, level );
920     item = item->nextSibling();
921   }
922 }
923
924 void OB_Browser::openBranch( QListViewItem* item, const int level )
925 {
926   if ( !item || level < 1 || !item->childCount() )
927     return;
928
929   item->setOpen( true );
930   while ( item )
931   {
932     openBranch( item, level - 1 );
933     item = item->nextSibling();
934   }
935 }