Salome HOME
Fix for bug with tree update.
[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->listView();
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( QtxListView::HeaderAuto, this );
80   myView->setAppropriate( myView->addColumn( "Data" ), false );
81   myView->setSorting( -1 );
82   myView->setRootIsDecorated( true );
83   myView->setSelectionMode( QListView::Extended );
84   myView->installEventFilter( this );
85   myView->viewport()->installEventFilter( this );
86
87   QVBoxLayout* main = new QVBoxLayout( this );
88   main->addWidget( myView );
89
90   myShowToolTips = true;
91   myTooltip = new ToolTip( this, myView->viewport() );
92
93   connect( myView, SIGNAL( dropped( QPtrList<QListViewItem>, QListViewItem*, int ) ),
94            this, SLOT( onDropped( QPtrList<QListViewItem>, QListViewItem*, int ) ) );
95   connect( myView, SIGNAL( selectionChanged() ), this, SIGNAL( selectionChanged() ) );
96
97   setRootObject( root );
98 }
99
100 OB_Browser::~OB_Browser()
101 {
102   myItems.clear();
103   delete myTooltip;
104 }
105
106 bool OB_Browser::rootIsDecorated() const
107 {
108   return myRootDecorated;
109 }
110
111 void OB_Browser::setRootIsDecorated( const bool decor )
112 {
113   if ( decor == rootIsDecorated() ) 
114     return;
115
116   myRootDecorated = decor;
117   updateTree();
118 }
119
120 int OB_Browser::autoOpenLevel() const
121 {
122   return myAutoOpenLevel;
123 }
124
125 void OB_Browser::setAutoOpenLevel( const int level )
126 {
127   if ( myAutoOpenLevel == level )
128     return;
129
130   myAutoOpenLevel = level;
131
132   autoOpenBranches();
133 }
134
135 bool OB_Browser::isShowToolTips()
136 {
137   return myShowToolTips;
138 }
139
140 void OB_Browser::setShowToolTips( const bool theDisplay )
141 {
142   myShowToolTips = theDisplay;
143 }
144
145 bool OB_Browser::isAutoUpdate() const
146 {
147   return myAutoUpdate;
148 }
149
150 void OB_Browser::setAutoUpdate( const bool on )
151 {
152   myAutoUpdate = on;
153 }
154
155 bool OB_Browser::isAutoDeleteObjects() const
156 {
157   return myAutoDelObjs;
158 }
159
160 void OB_Browser::setAutoDeleteObjects( const bool on )
161 {
162   myAutoDelObjs = on;
163 }
164
165 SUIT_DataObject* OB_Browser::getRootObject() const
166 {
167   return myRoot;
168 }
169
170 void OB_Browser::setRootObject( SUIT_DataObject* theRoot )
171 {
172   DataObjectKey curKey;
173   DataObjectMap selObjs, openObjs;
174   DataObjectKeyMap selKeys, openKeys;
175
176   int selNum = numberOfSelected();
177
178   SUIT_DataObject* curObj = 0;
179   if ( theRoot )
180     curObj = storeState( selObjs, openObjs, selKeys, openKeys, curKey );
181
182   if ( myRoot != theRoot && isAutoDeleteObjects() )
183     delete myRoot;
184
185   myRoot = theRoot;
186
187   createConnections( myRoot );
188
189   if ( myRoot )
190     updateView( myRoot );
191   else if ( listView() )
192   {
193     myItems.clear();
194     listView()->clear();
195   }
196
197   restoreState( selObjs, openObjs, curObj, selKeys, openKeys, curKey );
198
199   autoOpenBranches();
200
201   if ( selNum != numberOfSelected() )
202     emit selectionChanged();
203 }
204
205 int OB_Browser::numberOfSelected() const
206 {
207   int count = 0;
208   if ( listView() )
209   {
210     for ( QListViewItemIterator it( listView() ); it.current(); ++it )
211       if ( it.current()->isSelected() ) 
212         count++;
213   }
214   return count;
215 }
216
217 DataObjectList OB_Browser::getSelected() const
218 {
219   DataObjectList lst;
220   getSelected( lst );
221   return lst;
222 }
223
224 void OB_Browser::getSelected( DataObjectList& theObjList ) const
225 {
226   theObjList.clear();
227
228   if ( !listView() )
229     return;
230
231   for ( QListViewItemIterator it( listView() ); it.current(); ++it )
232   {
233     if ( it.current()->isSelected() ) 
234     {
235       SUIT_DataObject* obj = dataObject( it.current() );
236       if ( obj )
237         theObjList.append( obj );
238     }
239   }
240 }
241
242 void OB_Browser::setSelected( const SUIT_DataObject* theObject, const bool append )
243 {
244   DataObjectList lst;
245   lst.append( theObject );
246   setSelected( lst, append );
247 }
248
249 void OB_Browser::setSelected( const DataObjectList& theObjLst, const bool append )
250 {
251   QListView* lv = listView();
252
253   if ( !lv )
254     return;
255
256   bool changed = false;
257   bool block = lv->signalsBlocked();
258   lv->blockSignals( true );
259
260   QMap<QListViewItem*, int> map;
261   for ( DataObjectListIterator itr( theObjLst ); itr.current(); ++itr )
262     map.insert( listViewItem( itr.current() ), 0 );
263
264   for ( QListViewItemIterator it( lv ); it.current(); ++it )
265   {
266     QListViewItem* item = it.current();
267     if ( map.contains( item ) && !lv->isSelected( item ) )
268     {
269       changed = true;
270       lv->setSelected( item, true );
271     }
272     if ( !append && !map.contains( item ) && lv->isSelected( item ) )
273     {
274       changed = true;
275       lv->setSelected( item, false );
276     }
277   }
278
279   lv->blockSignals( block );
280
281   if ( changed )
282   {
283     int count = 0;
284     QListViewItem* sel = 0;
285     QListViewItem* cur = lv->currentItem();
286     for ( QListViewItemIterator iter( lv ); iter.current() && !sel; ++iter, count++ )
287     {
288       if ( iter.current()->isSelected() && cur == iter.current() )
289         sel = iter.current();
290     }
291
292     for ( QListViewItemIterator itr( lv ); itr.current() && !sel; ++itr )
293     {
294       if ( itr.current()->isSelected() )
295               sel = itr.current();
296     }
297
298     if ( sel )
299       lv->setCurrentItem( sel );
300
301     if ( sel && count == 1 )
302       lv->ensureItemVisible( sel );
303
304     emit selectionChanged();
305   }
306 }
307
308 bool OB_Browser::isOpen( SUIT_DataObject* theObject ) const
309 {
310   bool res = false;
311   if ( listView() )
312     res = listView()->isOpen( listViewItem( theObject ) );
313   return res;
314 }
315
316 void OB_Browser::setOpen( SUIT_DataObject* theObject, const bool theOpen )
317 {
318   if ( listView() )
319     listView()->setOpen( listViewItem( theObject ), theOpen );
320 }
321
322 SUIT_DataObject* OB_Browser::dataObjectAt( const QPoint& pos ) const
323 {
324   SUIT_DataObject* obj = 0;
325
326   QListView* lv = listView();
327   if ( lv )
328     obj = dataObject( lv->itemAt( pos ) );
329
330   return obj;
331 }
332
333 OB_Filter* OB_Browser::filter() const
334 {
335   return myView->filter();
336 }
337
338 void OB_Browser::setFilter( OB_Filter* f )
339 {
340   myView->setFilter( f );
341 }
342
343 int OB_Browser::addColumn( const QString& label, const int id, const int width )
344 {
345   return addColumn( QIconSet(), label, id, width );
346 }
347
348 int OB_Browser::addColumn( const QIconSet& icon, const QString& label, const int id, const int width )
349 {
350   QListView* lv = listView();
351   if ( !lv )
352     return -1;
353
354   int theId = id;
355   if ( theId < 0 )
356   {
357     while ( myColumnIds.contains( theId ) )
358       theId++;
359   }
360
361   if ( myColumnIds.contains( theId ) )
362     return -1; // can not reuse id
363
364   int sec = -1;
365   if ( icon.isNull() )
366     sec = lv->addColumn( label, width );
367   else
368     sec = lv->addColumn( icon, label, width );
369
370   if ( sec == -1 )
371     return -1;
372
373   myColumnIds.insert( theId, sec );
374   updateText();
375
376   return theId;
377 }
378
379 void OB_Browser::removeColumn( const int id )
380 {
381   QListView* lv = listView();
382   if ( !lv || !myColumnIds.contains( id ) )
383     return;
384
385   int sec = myColumnIds[id];
386   lv->removeColumn( sec );
387
388   // update map of column indeces
389   myColumnIds.remove( id );
390   for ( QMap<int, int>::iterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
391   {
392     if ( it.key() > id )
393       it.data()--;
394   }
395   updateText();
396 }
397
398 void OB_Browser::setNameTitle( const QString& label )
399 {
400   setNameTitle( QIconSet(), label );
401 }
402
403 void OB_Browser::setNameTitle( const QIconSet& icon, const QString& label )
404 {
405   QListView* lv = listView();
406   if ( !lv )
407     return;
408
409   if ( icon.isNull() )
410     lv->setColumnText( 0, label );
411   else
412     lv->setColumnText( 0, icon, label );
413 }
414
415 void OB_Browser::setColumnTitle( const int id, const QString& label )
416 {
417   setColumnTitle( id, QIconSet(), label );
418 }
419
420 void OB_Browser::setColumnTitle( const int id, const QIconSet& icon, const QString& label )
421 {
422   QListView* lv = listView();
423   if ( !lv || !myColumnIds.contains( id ) )
424     return;
425
426   if ( icon.isNull() )
427     lv->setColumnText( myColumnIds[id], label );
428   else
429     lv->setColumnText( myColumnIds[id], icon, label );
430 }
431
432 QString OB_Browser::nameTitle() const
433 {
434   return myView->columnText( 0 );
435 }
436
437 QString OB_Browser::columnTitle( const int id ) const
438 {
439   QString txt;
440   if ( myColumnIds.contains( id ) )
441     txt = myView->columnText( myColumnIds[id] );
442   return txt;
443 }
444
445 bool OB_Browser::isColumnVisible( const int id ) const
446 {
447   return myColumnIds.contains( id ) && myView->isShown( myColumnIds[id] );
448 }
449
450 void OB_Browser::setColumnShown( const int id, const bool on )
451 {
452   if ( !myColumnIds.contains( id ) )
453     return;
454
455   myView->setShown( myColumnIds[id], on );
456 }
457
458 QValueList<int> OB_Browser::columns() const
459 {
460   QValueList<int> lst;
461   for ( QMap<int, int>::ConstIterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
462     lst.append( it.key() );
463   return lst;
464 }
465
466 bool OB_Browser::appropriateColumn( const int id ) const
467 {
468   bool res = false;
469   if ( myColumnIds.contains( id ) )
470     res = myView->appropriate( myColumnIds[id] );
471   return res;
472 }
473
474 void OB_Browser::setAppropriateColumn( const int id, const bool on )
475 {
476   if ( !myColumnIds.contains( id ) )
477     return;
478
479   myView->setAppropriate( myColumnIds[id], on );
480 }
481
482 void OB_Browser::updateTree( SUIT_DataObject* o )
483 {
484   updateTree( o ? o : getRootObject(), false );
485 }
486
487 void OB_Browser::updateTree( SUIT_DataObject* obj, const bool notify )
488 {
489   if ( !obj )
490     return;
491
492   DataObjectKey curKey;
493   DataObjectMap selObjs, openObjs;
494   DataObjectKeyMap selKeys, openKeys;
495
496   int selNum = numberOfSelected();
497
498   SUIT_DataObject* curObj = storeState( selObjs, openObjs, selKeys, openKeys, curKey );
499
500   if ( notify )
501   {
502     bool upd = isAutoUpdate();
503     setAutoUpdate( false );
504     emit aboutRefresh();
505     setAutoUpdate( upd );
506   }
507
508   createConnections( obj );
509   updateView( obj );
510
511   restoreState( selObjs, openObjs, curObj, selKeys, openKeys, curKey );
512
513   autoOpenBranches();
514
515   if ( selNum != numberOfSelected() )
516     emit selectionChanged();
517 }
518
519 void OB_Browser::replaceTree( SUIT_DataObject* src, SUIT_DataObject* trg )
520 {
521   if ( !src || !trg || src->root() != getRootObject() )
522     return;
523
524   DataObjectKey curKey;
525   DataObjectMap selObjs, openObjs;
526   DataObjectKeyMap selKeys, openKeys;
527
528   int selNum = numberOfSelected();
529
530   SUIT_DataObject* curObj = storeState( selObjs, openObjs, selKeys, openKeys, curKey );
531
532   SUIT_DataObject* parent = src->parent();
533   int pos = parent ? parent->childPos( src ) : -1;
534
535   src->setParent( 0 );
536
537   if ( src != trg && isAutoDeleteObjects() )
538     delete src;
539
540   if ( parent && pos != -1 )
541     parent->insertChild( trg, pos );
542
543   trg->setParent( parent );
544
545   createConnections( trg );
546   updateView( trg );
547
548   restoreState( selObjs, openObjs, curObj, selKeys, openKeys, curKey );
549
550   autoOpenBranches();
551
552   if ( selNum != numberOfSelected() )
553     emit selectionChanged();
554 }
555
556 void OB_Browser::updateView( const SUIT_DataObject* theStartObj )
557 {
558   QListView* lv = listView();
559   if ( !lv )
560     return;
561
562   if ( !theStartObj || theStartObj->root() != getRootObject() )
563     return;
564
565   QListViewItem* after = 0;
566   QListViewItem* parent = 0;
567   QListViewItem* startItem = listViewItem( theStartObj );
568
569   if ( theStartObj->parent() )
570     parent = listViewItem( theStartObj->parent() );
571
572   QListViewItem* prv = 0;
573   QListViewItem* cur = parent ? parent->firstChild() : lv->firstChild();
574   while ( !after && cur )
575   {
576     if ( cur == startItem )
577       after = prv;
578
579     prv = cur;
580     cur = cur->nextSibling();
581   }
582
583   QPtrList<QListViewItem> delList;
584   if ( !startItem && theStartObj == getRootObject() )
585   {
586     for ( QListViewItem* item = lv->firstChild(); item; item = item->nextSibling() )
587       delList.append( item );
588   }
589   else
590     delList.append( startItem );
591
592   for ( QPtrListIterator<QListViewItem> it( delList ); it.current(); ++it )
593   {
594     removeReferences( it.current() );
595     delete it.current();
596   }
597
598   // for myRoot object, if myShowRoot==false, then creating multiple top-level QListViewItem-s
599   // (which will correspond to myRoot's children = Modules).  
600   if ( rootIsDecorated() && theStartObj == myRoot )
601   {
602     DataObjectList lst;
603     theStartObj->children( lst );
604     DataObjectListIterator it ( lst );
605     // iterating backward to preserve the order of elements in the tree
606     for ( it.toLast(); it.current(); --it )
607       createTree( it.current(), 0, 0 );
608   }
609   else
610     createTree( theStartObj, parent, after ? after : parent );
611 }
612
613 QListViewItem* OB_Browser::createTree( const SUIT_DataObject* obj,
614                                        QListViewItem* parent, QListViewItem* after )
615 {
616   if ( !obj )
617     return 0;
618   
619   QListViewItem* item = createItem( obj, parent, after );
620
621   DataObjectList lst;
622   obj->children( lst );
623   for ( DataObjectListIterator it ( lst ); it.current(); ++it )
624     createTree( it.current(), item );
625
626   if ( item )
627     item->setOpen( obj->isOpen() );
628
629   return item;
630 }
631
632 QListViewItem* OB_Browser::createItem( const SUIT_DataObject* o,
633                                        QListViewItem* parent, QListViewItem* after )
634 {
635   QListView* lv = listView();
636
637   if ( !lv || !o )
638     return 0;
639
640   QListViewItem* item = 0;
641   SUIT_DataObject* obj = (SUIT_DataObject*)o;
642
643   int type = -1;
644
645   switch ( obj->checkType() )
646   {
647   case SUIT_DataObject::CheckBox:
648     type = QCheckListItem::CheckBox;
649     break;
650   case SUIT_DataObject::RadioButton:
651     type = QCheckListItem::RadioButton;
652     break;
653   }
654
655   if ( parent )
656   {
657     if ( parent->childCount() && !after )
658     {
659       after = parent->firstChild();
660       while ( after->nextSibling() )
661         after = after->nextSibling();
662     }
663
664     if ( after )
665     {
666       if ( type == -1 )
667         item = new OB_ListItem( obj, parent, after );
668       else
669         item = new OB_CheckListItem( obj, parent, after, (QCheckListItem::Type)type );
670     }
671     else
672     {
673       if ( type == -1 )
674         item = new OB_ListItem( obj, parent );
675       else
676         item = new OB_CheckListItem( obj, parent,  (QCheckListItem::Type)type );
677     }
678   }
679   else // ROOT item
680   {
681     if ( type == -1 )
682       item = new OB_ListItem( obj, lv );
683     else
684       item = new OB_CheckListItem( obj, lv,  (QCheckListItem::Type)type );
685   }
686
687   myItems.insert( obj, item );
688
689   updateText( item );
690
691   return item;
692 }
693
694 void OB_Browser::adjustWidth()
695 {
696   if ( !listView() )
697     return;
698
699   listView()->setColumnWidth( 0, 0 );
700   if ( listView()->firstChild() )
701     adjustWidth( listView()->firstChild() );
702 }
703
704 void OB_Browser::adjustWidth( QListViewItem* item )
705 {
706   while ( item )
707   {
708     item->widthChanged( 0 );
709     if ( item->isOpen() )
710       adjustWidth( item->firstChild() );
711     item = item->nextSibling();
712   }
713 }
714
715 SUIT_DataObject* OB_Browser::dataObject( const QListViewItem* item ) const
716 {
717   SUIT_DataObject* obj = 0;
718
719   if ( item && item->rtti() == OB_ListItem::RTTI() )
720     obj = ((OB_ListItem*)item)->dataObject();
721   else if ( item && item->rtti() == OB_CheckListItem::RTTI() )
722     obj = ((OB_CheckListItem*)item)->dataObject();
723
724   return obj;
725 }
726
727 QListViewItem* OB_Browser::listViewItem( const SUIT_DataObject* obj ) const
728 {
729   QListViewItem* item = 0;
730
731   if ( myItems.contains( (SUIT_DataObject*)obj ) )
732     item = myItems[(SUIT_DataObject*)obj];
733
734   return item;
735 }
736
737 QListView* OB_Browser::listView() const
738 {
739   return myView;
740 }
741
742 void OB_Browser::removeReferences( QListViewItem* item )
743 {
744   if ( !item )
745     return;
746
747   SUIT_DataObject* obj = dataObject( item );
748   myItems.remove( obj );
749
750   QListViewItem* i = item->firstChild();
751   while ( i )
752   {
753     removeReferences( i );
754     i = i->nextSibling();
755   }
756 }
757
758 void OB_Browser::createConnections( SUIT_DataObject* obj )
759 {
760   if ( !obj )
761     return;
762
763   DataObjectList childList;
764   obj->children( childList, true );
765
766   childList.prepend( obj );
767
768   for ( DataObjectListIterator it( childList ); it.current(); ++it )
769     it.current()->connect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
770 }
771
772 SUIT_DataObject* OB_Browser::storeState( DataObjectMap& selObjs, DataObjectMap& openObjs,
773                                          DataObjectKeyMap& selKeys, DataObjectKeyMap& openKeys,
774                                          DataObjectKey& curKey ) const
775 {
776   QListView* lv = listView();
777   if ( !lv )
778     return 0;
779
780   SUIT_DataObject* curObj = dataObject( lv->currentItem() );
781
782   curKey = objectKey( curObj );
783
784   for ( QListViewItemIterator it( lv ); it.current(); ++it )
785   {
786     SUIT_DataObject* obj = dataObject( it.current() );
787     if ( !obj )
788       continue;
789
790     selObjs.insert( obj, lv->isSelected( it.current() ) );
791     openObjs.insert( obj, lv->isOpen( it.current() ) );
792     if ( lv->isSelected( it.current() ) )
793       selKeys.insert( objectKey( obj ), 0 );
794     if ( lv->isOpen( it.current() ) )
795       openKeys.insert( objectKey( obj ), 0 );
796   }
797
798   return curObj;
799 }
800
801 void OB_Browser::restoreState( const DataObjectMap& selObjs, const DataObjectMap& openObjs,
802                                const SUIT_DataObject* curObj, const DataObjectKeyMap& selKeys,
803                                const DataObjectKeyMap& openKeys, const DataObjectKey& curKey )
804 {
805   QListView* lv = listView();
806   if ( !lv )
807     return;
808
809   bool block = lv->signalsBlocked();
810   lv->blockSignals( true );
811
812   QListViewItem* curItem = 0;
813   for ( QListViewItemIterator it( lv ); it.current(); ++it )
814   {
815     QListViewItem* item = it.current();
816     SUIT_DataObject* obj = dataObject( item );
817
818     if ( !obj )
819       continue;
820
821     DataObjectKey key = objectKey( obj );
822
823     if ( selObjs.contains( obj ) )
824     {
825       if ( selObjs[obj] && !lv->isSelected( item ) )
826         lv->setSelected( item, true );
827     }
828     else if ( !key.isNull() && selKeys.contains( key ) && !lv->isSelected( item ) )
829       lv->setSelected( item, true );
830
831     if ( openObjs.contains( obj ) )
832     {
833       if ( openObjs[obj] )
834         lv->setOpen( item, true );
835     }
836     else if ( !key.isNull() && openKeys.contains( key ) )
837       lv->setOpen( item, true );
838
839     if ( !curItem && ( curObj == obj || ( !curKey.isNull() && curKey == key )) )
840       curItem = item;
841   }
842
843   if ( curItem )
844     lv->setCurrentItem( curItem );
845
846   lv->blockSignals( block );
847 }
848
849 OB_Browser::DataObjectKey OB_Browser::objectKey( QListViewItem* i ) const
850 {
851   return objectKey( dataObject( i ) );
852 }
853
854 OB_Browser::DataObjectKey OB_Browser::objectKey( SUIT_DataObject* obj ) const
855 {
856   if ( !obj )
857     return 0;
858
859   return DataObjectKey( obj->key() );
860 }
861
862 void OB_Browser::keyPressEvent( QKeyEvent* e )
863 {
864   if ( e->key() == Qt::Key_F5 )
865     updateTree();
866
867   QFrame::keyPressEvent( e );
868 }
869
870 void OB_Browser::onExpand()
871 {
872   DataObjectList selected;
873   getSelected( selected );
874   for ( DataObjectListIterator itr( selected ); itr.current(); ++itr )
875     expand( listViewItem( itr.current() ) );
876 }
877
878 void OB_Browser::onRefresh()
879 {
880   updateTree( 0, true );
881 }
882
883 void OB_Browser::onColumnVisible( int id )
884 {
885   setColumnShown( id, !isColumnVisible( id ) );
886 }
887
888 void OB_Browser::onDestroyed( SUIT_DataObject* obj )
889 {
890   removeObject( obj );
891 }
892
893 void OB_Browser::onDropped( QPtrList<QListViewItem> items, QListViewItem* item, int action )
894 {
895   SUIT_DataObject* obj = dataObject( item );
896   if ( !obj )
897     return;
898
899   DataObjectList lst;
900   for ( QPtrListIterator<QListViewItem> it( items ); it.current(); ++it )
901   {
902     SUIT_DataObject* o = dataObject( it.current() );
903     if ( o )
904       lst.append( o );
905   }
906
907   if ( !lst.isEmpty() )
908     emit dropped( lst, obj, action );
909 }
910
911 void OB_Browser::updateText()
912 {
913   if ( myColumnIds.isEmpty() )
914     return;
915
916   QListView* lv = listView();
917   if ( !lv )
918     return;
919
920   for ( QListViewItemIterator it( lv ); it.current(); ++it )
921   {
922     SUIT_DataObject* obj = dataObject( it.current() );
923     if ( !obj )
924       continue;
925
926     for( QMap<int, int>::iterator itr = myColumnIds.begin(); itr != myColumnIds.end(); ++itr )
927       it.current()->setText( itr.data(), obj->text( itr.key() ) );
928   }
929 }
930
931 void OB_Browser::updateText( QListViewItem* item )
932 {
933   SUIT_DataObject* obj = dataObject( item );
934   if ( !obj )
935     return;
936
937   for( QMap<int, int>::iterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
938     item->setText( it.data(), obj->text( it.key() ) );
939 }
940
941 bool OB_Browser::eventFilter( QObject* o, QEvent* e )
942 {
943   if ( o == myView && e->type() == QEvent::ContextMenu )
944   {
945     QContextMenuEvent* ce = (QContextMenuEvent*)e;
946     if ( ce->reason() != QContextMenuEvent::Mouse )
947       contextMenuRequest( ce );
948     return true;
949   }
950   if ( o == myView->viewport() && e->type() == QEvent::MouseButtonRelease )
951   {
952     QMouseEvent* me = (QMouseEvent*)e;
953     if ( me->button() == RightButton )
954     {
955       QContextMenuEvent ce( QContextMenuEvent::Mouse, me->pos(), me->globalPos(), me->state() );
956       contextMenuRequest( &ce );
957       return true;
958     }
959   }
960
961   return QFrame::eventFilter( o, e );
962 }
963
964 void OB_Browser::contextMenuPopup( QPopupMenu* menu )
965 {
966   QValueList<int> cols;
967   for ( QMap<int, int>::ConstIterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
968   {
969     if ( appropriateColumn( it.key() ) )
970       cols.append( it.key() );
971   }
972
973   uint num = menu->count();
974   menu->setCheckable( true );
975   for ( QValueList<int>::const_iterator iter = cols.begin(); iter != cols.end(); ++iter )
976   {
977     QString name = columnTitle( *iter );
978     if ( name.isEmpty() )
979       continue;
980
981     int id = menu->insertItem( name, this, SLOT( onColumnVisible( int ) ) );
982     menu->setItemChecked( id, isColumnVisible( *iter ) );
983     menu->setItemParameter( id, *iter );
984   }
985   if ( menu->count() != num )
986     menu->insertSeparator();
987
988   DataObjectList selected;
989   getSelected( selected );
990
991   bool closed = false;
992   for ( DataObjectListIterator itr( selected ); itr.current() && !closed; ++itr )
993     closed = hasClosed( listViewItem( itr.current() ) );
994
995   if ( closed )
996   {
997     menu->insertItem( tr( "MEN_EXPAND_ALL" ), this, SLOT( onExpand() ) );
998     menu->insertSeparator();
999   }
1000   menu->insertItem( tr( "MEN_REFRESH" ), this, SLOT( onRefresh() ) );
1001 }
1002
1003 void OB_Browser::expand( QListViewItem* item )
1004 {
1005   if ( !item )
1006     return;
1007
1008   item->setOpen( true );
1009   for ( QListViewItem* child = item->firstChild(); child; child = child->nextSibling() )
1010     expand( child );
1011 }
1012
1013 bool OB_Browser::hasClosed( QListViewItem* item ) const
1014 {
1015   if ( !item )
1016     return false;
1017
1018   if ( item->childCount() && !item->isOpen() )
1019     return true;
1020
1021   bool has = false;
1022   for ( QListViewItem* child = item->firstChild(); child && !has; child = child->nextSibling() )
1023     has = hasClosed( child );
1024
1025   return has;
1026 }
1027
1028 void OB_Browser::removeObject( SUIT_DataObject* obj, const bool autoUpd )
1029 {
1030   if ( !obj )
1031     return;
1032
1033   // Removing list view items from <myItems> recursively for all children.
1034   // Otherwise, "delete item" line will destroy all item's children,
1035   // and <myItems> will contain invalid pointers (see ~QListViewItem() description in Qt docs)
1036   DataObjectList childList;
1037   obj->children( childList );
1038   for ( DataObjectListIterator it( childList ); it.current(); ++it )
1039     removeObject( it.current(), false );
1040
1041   QListViewItem* item = listViewItem( obj );
1042
1043   myItems.remove( obj );
1044
1045   if ( obj == myRoot )
1046     myRoot = 0;
1047
1048   if ( !autoUpd )
1049     return;
1050
1051   if ( isAutoUpdate() )
1052   {
1053     SUIT_DataObject* pObj = item && item->parent() ? dataObject( item->parent() ) : 0;
1054     updateTree( pObj );
1055   }
1056   else
1057     delete item;
1058 }
1059
1060 void OB_Browser::autoOpenBranches()
1061 {
1062   int level = autoOpenLevel();
1063   QListView* lv = listView();
1064   if ( !lv || level < 1 )
1065     return;
1066
1067   QListViewItem* item = lv->firstChild();
1068   while ( item )
1069   {
1070     openBranch( item, level );
1071     item = item->nextSibling();
1072   }
1073 }
1074
1075 void OB_Browser::openBranch( QListViewItem* item, const int level )
1076 {
1077   if ( !item || level < 1 || !item->childCount() )
1078     return;
1079
1080   item->setOpen( true );
1081   while ( item )
1082   {
1083     openBranch( item->firstChild(), level - 1 );
1084     item = item->nextSibling();
1085   }
1086 }