Salome HOME
Join modifications from branch OCC_development_for_3_2_0a2
[modules/gui.git] / src / ObjBrowser / OB_Browser.cxx
1 // Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
2 // 
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either 
6 // version 2.1 of the License.
7 // 
8 // This library is distributed in the hope that it will be useful 
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public  
14 // License along with this library; if not, write to the Free Software 
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/
18 //
19 #include "OB_Browser.h"
20
21 #include "OB_Filter.h"
22 #include "OB_ListItem.h"
23 #include "OB_ListView.h"
24
25 #include <SUIT_DataObjectIterator.h>
26 #include <SUIT_TreeSync.h>
27
28 #include <qcursor.h>
29 #include <qlayout.h>
30 #include <qtooltip.h>
31 #include <qpainter.h>
32 #include <qwmatrix.h>
33 #include <qlistview.h>
34 #include <qpopupmenu.h>
35 #include <qdatetime.h>
36
37 #include <time.h>
38
39 /*!
40     Class: OB_Browser::ToolTip
41     Descr: Tool tip for OB_Browser.
42 */
43
44 class OB_Browser::ToolTip : public QToolTip
45 {
46 public:
47   ToolTip( OB_Browser* b, QWidget* p = 0 );
48   virtual ~ToolTip();
49
50   void        maybeTip( const QPoint& );
51
52 private:
53   OB_Browser* myBrowser;
54 };
55
56 OB_Browser::ToolTip::ToolTip( OB_Browser* b, QWidget* p )
57 : QToolTip( p ),
58 myBrowser( b )
59 {
60 }
61
62 OB_Browser::ToolTip::~ToolTip()
63 {
64 }
65
66 void OB_Browser::ToolTip::maybeTip( const QPoint& pos )
67 {
68   if ( !parentWidget() || !myBrowser || !myBrowser->isShowToolTips() )
69           return;
70
71   QListView* lv = myBrowser->listView();
72
73   QListViewItem* item = lv->itemAt( pos );
74   SUIT_DataObject* obj = myBrowser->dataObject( item );
75   if ( !obj )
76     return;
77
78   QString aText = obj->toolTip();
79
80   if ( aText.isEmpty() )
81     return;
82
83   QRect aRect = lv->itemRect( item );
84
85   tip( aRect, aText );
86 }
87
88
89 typedef SUIT_DataObject*   ObjPtr;
90 typedef OB_ListItem*       ItemPtr;
91 /*!
92     Class: OB_BrowserSync
93     Descr: Auxiliary class for synchronizing tree of SUIT_DataObjects and list view items
94 */
95
96 class OB_BrowserSync
97 {
98 public:
99   OB_BrowserSync( OB_Browser* );
100   bool     isEqual( const ObjPtr&, const ItemPtr& ) const;
101   ObjPtr   nullSrc() const;
102   ItemPtr  nullTrg() const;
103   ItemPtr  createItem( const ObjPtr&, const ItemPtr&, const ItemPtr&, const bool ) const;
104   void     updateItem( const ItemPtr& ) const;
105   void     deleteItemWithChildren( const ItemPtr& ) const;
106   void     children( const ObjPtr&, QValueList<ObjPtr>& ) const;
107   void     children( const ItemPtr&, QValueList<ItemPtr>& ) const;
108   ItemPtr  parent( const ItemPtr& ) const;
109 private:
110   bool     needUpdate( const ItemPtr& ) const;
111   OB_Browser*   myBrowser;
112 };
113
114
115 OB_BrowserSync::OB_BrowserSync( OB_Browser* ob )
116 : myBrowser( ob )
117 {
118 }
119
120 bool OB_BrowserSync::needUpdate( const ItemPtr& item ) const
121 {
122   bool update = false;
123   if ( item ) {
124     SUIT_DataObject* obj = item->dataObject();
125     if ( obj ) {
126       // 1. check text
127       update = ( item->text( 0 ) != obj->name() );
128       if ( !update ) { 
129         // 2. check pixmap (compare serialNumber()-s)
130         QPixmap objPix = obj->icon();
131         const QPixmap* itemPix = item->pixmap( 0 );
132         update = (  objPix.isNull() && (  itemPix && !itemPix->isNull() ) ) || 
133                  ( !objPix.isNull() && ( !itemPix ||  itemPix->isNull() ) ); 
134         if ( !update && !objPix.isNull() && itemPix && !itemPix->isNull() ) {
135           int aIconW = objPix.width();
136           if( aIconW > 20 ) {
137             QWMatrix aM;
138             double aScale = 20.0 / aIconW;
139             aM.scale( aScale, aScale );
140             objPix = objPix.xForm( aM );
141           }
142           update = ( objPix.serialNumber() != itemPix->serialNumber() );
143         }
144       }
145     }
146   }
147   return update;
148 }
149
150 void OB_BrowserSync::updateItem( const ItemPtr& p ) const
151 {
152   if ( p && needUpdate( p ) ) { 
153     //    printf( "--- needUpdate for %s = true ---\n", p->text( 0 ).latin1() );
154     p->update();
155   }
156 }
157
158 ItemPtr OB_BrowserSync::createItem( const ObjPtr& src,
159                                     const ItemPtr& parent, const ItemPtr& after,
160                                     const bool prepend ) const
161 {
162   ItemPtr i = myBrowser ? dynamic_cast<ItemPtr>( myBrowser->createItem( src, parent, after, prepend ) ) : 0;
163   if( i )
164     i->setOpen( src->isOpen() );
165   return i;
166 }
167
168 void OB_BrowserSync::deleteItemWithChildren( const ItemPtr& i ) const
169 {
170   if( myBrowser && myBrowser->myItems.contains( i->dataObject() ) )
171   {
172     myBrowser->removeReferences( i );
173     delete i;
174   }
175 }
176
177 bool OB_BrowserSync::isEqual( const ObjPtr& p, const ItemPtr& q ) const
178 {
179   return ( !p && !q ) || ( p && q && q->dataObject()==p );
180 }
181
182 ObjPtr OB_BrowserSync::nullSrc() const
183 {
184   return 0;
185 }
186
187 ItemPtr OB_BrowserSync::nullTrg() const
188 {
189   return 0;
190 }
191
192 void OB_BrowserSync::children( const ObjPtr& p, QValueList<ObjPtr>& ch ) const
193 {
194   DataObjectList l;
195   if( p )
196   {
197     p->children( l );
198     ch.clear();
199     for( SUIT_DataObject* o = l.first(); o; o = l.next() )
200       ch.append( o );
201   }
202 }
203
204 void OB_BrowserSync::children( const ItemPtr& p, QValueList<ItemPtr>& ch ) const
205 {
206   for( QListViewItem* item = p->firstChild(); item; item = item->nextSibling() )
207   {
208     ItemPtr p = dynamic_cast<ItemPtr>( item );
209     if( p )
210       ch.append( p );
211   }
212 }
213
214 ItemPtr OB_BrowserSync::parent( const ItemPtr& p ) const
215 {
216   return p ? dynamic_cast<ItemPtr>( p->parent() ) : 0;
217 }
218
219
220 /*!
221     Class: OB_Browser
222     Descr: Hierarchical tree object browser.
223 */
224
225 OB_Browser::OB_Browser( QWidget* parent, SUIT_DataObject* root )
226 : QFrame( parent ),
227
228 myRoot( 0 ),
229 myTooltip( 0 ),
230 myAutoOpenLevel( 0 ),
231 myAutoUpdate( false ),
232 myAutoDelObjs( false ),
233 myRootDecorated( true )
234 {
235   myView = new OB_ListView( QtxListView::HeaderAuto, this );
236   myView->setAppropriate( myView->addColumn( "Data" ), false );
237   myView->setSorting( -1 );
238   myView->setRootIsDecorated( true );
239   myView->setSelectionMode( QListView::Extended );
240   myView->installEventFilter( this );
241   myView->viewport()->installEventFilter( this );
242
243   QVBoxLayout* main = new QVBoxLayout( this );
244   main->addWidget( myView );
245
246   myShowToolTips = true;
247   myTooltip = new ToolTip( this, myView->viewport() );
248
249   connect( myView, SIGNAL( dropped( QPtrList<QListViewItem>, QListViewItem*, int ) ),
250            this, SLOT( onDropped( QPtrList<QListViewItem>, QListViewItem*, int ) ) );
251   connect( myView, SIGNAL( selectionChanged() ), this, SIGNAL( selectionChanged() ) );
252   connect( myView, SIGNAL( doubleClicked( QListViewItem* ) ),
253            this, SLOT( onDoubleClicked( QListViewItem* ) ) );
254
255   setRootObject( root );
256
257   setModified();
258 }
259
260 OB_Browser::~OB_Browser()
261 {
262   myItems.clear();
263   delete myTooltip;
264 }
265
266 bool OB_Browser::rootIsDecorated() const
267 {
268   return myRootDecorated;
269 }
270
271 void OB_Browser::setRootIsDecorated( const bool decor )
272 {
273   if ( decor == rootIsDecorated() ) 
274     return;
275
276   myRootDecorated = decor;
277   updateTree( 0, false );
278 }
279
280 int OB_Browser::autoOpenLevel() const
281 {
282   return myAutoOpenLevel;
283 }
284
285 void OB_Browser::setAutoOpenLevel( const int level )
286 {
287   if ( myAutoOpenLevel == level )
288     return;
289
290   myAutoOpenLevel = level;
291
292   autoOpenBranches();
293 }
294
295 bool OB_Browser::isShowToolTips()
296 {
297   return myShowToolTips;
298 }
299
300 void OB_Browser::setShowToolTips( const bool theDisplay )
301 {
302   myShowToolTips = theDisplay;
303 }
304
305 bool OB_Browser::isAutoUpdate() const
306 {
307   return myAutoUpdate;
308 }
309
310 void OB_Browser::setAutoUpdate( const bool on )
311 {
312   myAutoUpdate = on;
313 }
314
315 bool OB_Browser::isAutoDeleteObjects() const
316 {
317   return myAutoDelObjs;
318 }
319
320 void OB_Browser::setAutoDeleteObjects( const bool on )
321 {
322   myAutoDelObjs = on;
323 }
324
325 SUIT_DataObject* OB_Browser::getRootObject() const
326 {
327   return myRoot;
328 }
329
330 void OB_Browser::setRootObject( SUIT_DataObject* theRoot )
331 {
332   DataObjectKey curKey;
333   DataObjectMap selObjs, openObjs;
334   DataObjectKeyMap selKeys, openKeys;
335
336   int selNum = numberOfSelected();
337
338   SUIT_DataObject* curObj = 0;
339   if ( theRoot )
340     curObj = storeState( selObjs, openObjs, selKeys, openKeys, curKey );
341
342   removeConnections( myRoot );
343   if ( myRoot != theRoot && isAutoDeleteObjects() )
344     delete myRoot;
345
346   myRoot = theRoot;
347
348   createConnections( myRoot );
349
350   if ( myRoot )
351     updateView( myRoot );
352   else if ( listView() )
353   {
354     myItems.clear();
355     listView()->clear();
356   }
357
358   restoreState( selObjs, openObjs, curObj, selKeys, openKeys, curKey );
359
360   autoOpenBranches();
361
362   setModified();
363
364   if ( selNum != numberOfSelected() )
365     emit selectionChanged();
366 }
367
368 int OB_Browser::numberOfSelected() const
369 {
370   int count = 0;
371   if ( listView() )
372   {
373     for ( QListViewItemIterator it( listView() ); it.current(); ++it )
374       if ( it.current()->isSelected() ) 
375         count++;
376   }
377   return count;
378 }
379
380 DataObjectList OB_Browser::getSelected() const
381 {
382   DataObjectList lst;
383   getSelected( lst );
384   return lst;
385 }
386
387 void OB_Browser::getSelected( DataObjectList& theObjList ) const
388 {
389   theObjList.clear();
390
391   if ( !listView() )
392     return;
393
394   for ( QListViewItemIterator it( listView() ); it.current(); ++it )
395   {
396     if ( it.current()->isSelected() ) 
397     {
398       SUIT_DataObject* obj = dataObject( it.current() );
399       if ( obj )
400         theObjList.append( obj );
401     }
402   }
403 }
404
405 void OB_Browser::setSelected( const SUIT_DataObject* theObject, const bool append )
406 {
407   DataObjectList lst;
408   lst.append( theObject );
409   setSelected( lst, append );
410 }
411
412 void OB_Browser::setSelected( const DataObjectList& theObjLst, const bool append )
413 {
414   QListView* lv = listView();
415
416   if ( !lv )
417     return;
418
419   bool changed = false;
420   bool block = lv->signalsBlocked();
421   lv->blockSignals( true );
422
423   QMap<QListViewItem*, int> map;
424   for ( DataObjectListIterator itr( theObjLst ); itr.current(); ++itr )
425     map.insert( listViewItem( itr.current() ), 0 );
426
427   for ( QListViewItemIterator it( lv ); it.current(); ++it )
428   {
429     QListViewItem* item = it.current();
430     if ( map.contains( item ) && !lv->isSelected( item ) )
431     {
432       changed = true;
433       lv->setSelected( item, true );
434     }
435     if ( !append && !map.contains( item ) && lv->isSelected( item ) )
436     {
437       changed = true;
438       lv->setSelected( item, false );
439     }
440   }
441
442   lv->blockSignals( block );
443
444   if ( changed )
445   {
446     int count = 0;
447     QListViewItem* sel = 0;
448     QListViewItem* cur = lv->currentItem();
449     for ( QListViewItemIterator iter( lv ); iter.current() && !sel; ++iter, count++ )
450     {
451       if ( iter.current()->isSelected() && cur == iter.current() )
452         sel = iter.current();
453     }
454
455     for ( QListViewItemIterator itr( lv ); itr.current() && !sel; ++itr )
456     {
457       if ( itr.current()->isSelected() )
458               sel = itr.current();
459     }
460
461     if ( sel )
462       lv->setCurrentItem( sel );
463
464     if ( sel && count == 1 )
465       lv->ensureItemVisible( sel );
466
467     emit selectionChanged();
468   }
469 }
470
471 bool OB_Browser::isOpen( SUIT_DataObject* theObject ) const
472 {
473   bool res = false;
474   if ( listView() )
475     res = listView()->isOpen( listViewItem( theObject ) );
476   return res;
477 }
478
479 void OB_Browser::setOpen( SUIT_DataObject* theObject, const bool theOpen )
480 {
481   if ( listView() )
482     listView()->setOpen( listViewItem( theObject ), theOpen );
483 }
484
485 SUIT_DataObject* OB_Browser::dataObjectAt( const QPoint& pos ) const
486 {
487   SUIT_DataObject* obj = 0;
488
489   QListView* lv = listView();
490   if ( lv )
491     obj = dataObject( lv->itemAt( pos ) );
492
493   return obj;
494 }
495
496 OB_Filter* OB_Browser::filter() const
497 {
498   return myView->filter();
499 }
500
501 void OB_Browser::setFilter( OB_Filter* f )
502 {
503   myView->setFilter( f );
504 }
505
506 int OB_Browser::addColumn( const QString& label, const int id, const int width )
507 {
508   return addColumn( QIconSet(), label, id, width );
509 }
510
511 int OB_Browser::addColumn( const QIconSet& icon, const QString& label, const int id, const int width )
512 {
513   QListView* lv = listView();
514   if ( !lv )
515     return -1;
516
517   int theId = id;
518   if ( theId < 0 )
519   {
520     while ( myColumnIds.contains( theId ) )
521       theId++;
522   }
523
524   if ( myColumnIds.contains( theId ) )
525     return -1; // can not reuse id
526
527   int sec = -1;
528   if ( icon.isNull() )
529     sec = lv->addColumn( label, width );
530   else
531     sec = lv->addColumn( icon, label, width );
532
533   if ( sec == -1 )
534     return -1;
535
536   myColumnIds.insert( theId, sec );
537   updateText();
538
539   return theId;
540 }
541
542 void OB_Browser::removeColumn( const int id )
543 {
544   QListView* lv = listView();
545   if ( !lv || !myColumnIds.contains( id ) )
546     return;
547
548   int sec = myColumnIds[id];
549   lv->removeColumn( sec );
550
551   // update map of column indeces
552   myColumnIds.remove( id );
553   for ( QMap<int, int>::iterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
554   {
555     if ( it.key() > id )
556       it.data()--;
557   }
558   updateText();
559 }
560
561 void OB_Browser::setNameTitle( const QString& label )
562 {
563   setNameTitle( QIconSet(), label );
564 }
565
566 void OB_Browser::setNameTitle( const QIconSet& icon, const QString& label )
567 {
568   QListView* lv = listView();
569   if ( !lv )
570     return;
571
572   if ( icon.isNull() )
573     lv->setColumnText( 0, label );
574   else
575     lv->setColumnText( 0, icon, label );
576 }
577
578 void OB_Browser::setColumnTitle( const int id, const QString& label )
579 {
580   setColumnTitle( id, QIconSet(), label );
581 }
582
583 void OB_Browser::setColumnTitle( const int id, const QIconSet& icon, const QString& label )
584 {
585   QListView* lv = listView();
586   if ( !lv || !myColumnIds.contains( id ) )
587     return;
588
589   if ( icon.isNull() )
590     lv->setColumnText( myColumnIds[id], label );
591   else
592     lv->setColumnText( myColumnIds[id], icon, label );
593 }
594
595 QString OB_Browser::nameTitle() const
596 {
597   return myView->columnText( 0 );
598 }
599
600 QString OB_Browser::columnTitle( const int id ) const
601 {
602   QString txt;
603   if ( myColumnIds.contains( id ) )
604     txt = myView->columnText( myColumnIds[id] );
605   return txt;
606 }
607
608 bool OB_Browser::isColumnVisible( const int id ) const
609 {
610   return myColumnIds.contains( id ) && myView->isShown( myColumnIds[id] );
611 }
612
613 void OB_Browser::setColumnShown( const int id, const bool on )
614 {
615   if ( !myColumnIds.contains( id ) )
616     return;
617
618   myView->setShown( myColumnIds[id], on );
619 }
620
621 void OB_Browser::setWidthMode( QListView::WidthMode mode )
622 {
623   for ( int i = 0, n = myView->columns(); i < n; i++ )
624     myView->setColumnWidthMode( i, mode );
625 }
626
627 QValueList<int> OB_Browser::columns() const
628 {
629   QValueList<int> lst;
630   for ( QMap<int, int>::ConstIterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
631     lst.append( it.key() );
632   return lst;
633 }
634
635 bool OB_Browser::appropriateColumn( const int id ) const
636 {
637   bool res = false;
638   if ( myColumnIds.contains( id ) )
639     res = myView->appropriate( myColumnIds[id] );
640   return res;
641 }
642
643 void OB_Browser::setAppropriateColumn( const int id, const bool on )
644 {
645   if ( !myColumnIds.contains( id ) )
646     return;
647
648   myView->setAppropriate( myColumnIds[id], on );
649 }
650
651 void OB_Browser::updateTree( SUIT_DataObject* obj, const bool autoOpen )
652 {
653 //  QTime t1 = QTime::currentTime();
654
655   if ( !obj && !(obj = getRootObject()) )
656     return;
657
658   DataObjectKey curKey;
659   DataObjectMap selObjs, openObjs;
660   DataObjectKeyMap selKeys, openKeys;
661
662   int selNum = numberOfSelected();
663
664   SUIT_DataObject* curObj = storeState( selObjs, openObjs, selKeys, openKeys, curKey );
665
666   updateView( obj );
667
668   restoreState( selObjs, openObjs, curObj, selKeys, openKeys, curKey );
669
670   if( autoOpen )
671     autoOpenBranches();
672
673   setModified();
674
675   if ( selNum != numberOfSelected() )
676     emit selectionChanged();
677
678 //  QTime t2 = QTime::currentTime();
679 //  qDebug( QString( "update tree time = %1 msecs" ).arg( t1.msecsTo( t2 ) ) );
680 }
681
682 void OB_Browser::replaceTree( SUIT_DataObject* src, SUIT_DataObject* trg )
683 {
684   if ( !src || !trg || src == trg || src->root() != getRootObject() )
685     return;
686
687   DataObjectKey curKey;
688   DataObjectMap selObjs, openObjs;
689   DataObjectKeyMap selKeys, openKeys;
690
691   int selNum = numberOfSelected();
692
693   SUIT_DataObject* curObj = storeState( selObjs, openObjs, selKeys, openKeys, curKey );
694
695   SUIT_DataObject* parent = src->parent();
696   int pos = parent ? parent->childPos( src ) : -1;
697
698   src->setParent( 0 );
699
700   removeConnections( src );
701   if ( isAutoDeleteObjects() )
702     delete src;
703
704   if ( parent && pos != -1 )
705     parent->insertChild( trg, pos );
706
707   trg->setParent( parent );
708
709   updateView( trg );
710   createConnections( trg );
711
712   restoreState( selObjs, openObjs, curObj, selKeys, openKeys, curKey );
713
714   autoOpenBranches();
715
716   setModified();
717
718   if ( selNum != numberOfSelected() )
719     emit selectionChanged();
720 }
721
722 void OB_Browser::updateView( SUIT_DataObject* startObj )
723 {
724   QListView* lv = listView();
725   if ( !lv )
726     return;
727
728   if ( !startObj || startObj->root() != getRootObject() )
729     return;
730
731   if ( startObj == myRoot )
732   {
733     DataObjectList ch;
734     myRoot->children( ch );
735
736     ItemMap exist;
737     QListViewItem* st = lv->firstChild();
738     for( ; st; st =  st->nextSibling() )
739     {
740       OB_ListItem* ob_item = dynamic_cast<OB_ListItem*>( st );
741       exist.insert( ob_item->dataObject(), ob_item );
742     }
743
744     SUIT_DataObject* local_root = ch.first();
745     for( ; local_root; local_root = ch.next() )
746     {
747       OB_BrowserSync sync( this );
748       OB_ListItem* local_item = dynamic_cast<OB_ListItem*>( listViewItem( local_root ) );
749       synchronize<ObjPtr,ItemPtr,OB_BrowserSync>( local_root, local_item, sync );
750       exist[local_root] = 0;
751     }
752
753     ItemMap::const_iterator anIt = exist.begin(), aLast = exist.end();
754     for( ; anIt!=aLast; anIt++ )
755     {
756       if( anIt.data() ) // exist[local_root]==1 -> this local root was NOT in data model, should be removed
757       {
758         removeReferences( anIt.data() );
759         OB_ListItem* item = dynamic_cast<OB_ListItem*>( anIt.data() );
760         if( item && myItems.contains( item->dataObject() ) )
761           delete anIt.data();
762       }
763     }
764   }
765   else
766   {
767     OB_BrowserSync sync( this );
768     OB_ListItem* startItem = dynamic_cast<OB_ListItem*>( listViewItem( startObj ) );
769     synchronize<ObjPtr,ItemPtr,OB_BrowserSync>( startObj, startItem, sync );
770   }
771 }
772
773 QListViewItem* OB_Browser::createItem( const SUIT_DataObject* o, QListViewItem* parent,
774                                        QListViewItem* after, const bool prepend )
775 {
776   QListView* lv = listView();
777
778   if ( !lv || !o )
779     return 0;
780
781   QListViewItem* item = 0;
782   SUIT_DataObject* obj = (SUIT_DataObject*)o;
783
784   int type = -1;
785
786   switch ( obj->checkType() )
787   {
788   case SUIT_DataObject::CheckBox:
789     type = QCheckListItem::CheckBox;
790     break;
791   case SUIT_DataObject::RadioButton:
792     type = QCheckListItem::RadioButton;
793     break;
794   }
795
796   if ( parent )
797   {
798     if ( after ) 
799     {
800       if ( type == -1 )
801         item = new OB_ListItem( obj, parent, after );
802       else
803         item = new OB_CheckListItem( obj, parent, after, (QCheckListItem::Type)type );
804     }
805     else if ( prepend )
806     {
807       if ( type == -1 )
808         item = new OB_ListItem( obj, parent );
809       else
810         item = new OB_CheckListItem( obj, parent,  (QCheckListItem::Type)type );
811     }
812     else // append
813     {
814       after = parent->firstChild();
815       while ( after && after->nextSibling() )
816         after = after->nextSibling();
817       if ( type == -1 )
818         item = new OB_ListItem( obj, parent, after );
819       else
820         item = new OB_CheckListItem( obj, parent, after, (QCheckListItem::Type)type );
821     }
822   }
823   else
824   {
825     if ( after ) 
826     {
827       if ( type == -1 )
828         item = new OB_ListItem( obj, lv, after );
829       else
830         item = new OB_CheckListItem( obj, lv, after, (QCheckListItem::Type)type );
831     }
832     else if ( prepend )
833     {
834       if ( type == -1 )
835         item = new OB_ListItem( obj, lv );
836       else
837         item = new OB_CheckListItem( obj, lv,  (QCheckListItem::Type)type );
838     }
839     else // append
840     {
841       after = lv->firstChild();
842       while ( after && after->nextSibling() )
843         after = after->nextSibling();
844       if ( type == -1 )
845         item = new OB_ListItem( obj, lv, after );
846       else
847         item = new OB_CheckListItem( obj, lv, after, (QCheckListItem::Type)type );
848     }
849   }
850
851   myItems.insert( obj, item );
852   obj->connect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
853   updateText( item );
854
855   return item;
856 }
857
858 void OB_Browser::adjustWidth()
859 {
860   if ( !listView() )
861     return;
862
863   listView()->setColumnWidth( 0, 0 );
864   if ( listView()->firstChild() )
865     adjustWidth( listView()->firstChild() );
866 }
867
868 void OB_Browser::adjustWidth( QListViewItem* item )
869 {
870   while ( item )
871   {
872     item->widthChanged( 0 );
873     if ( item->isOpen() )
874       adjustWidth( item->firstChild() );
875     item = item->nextSibling();
876   }
877 }
878
879 SUIT_DataObject* OB_Browser::dataObject( const QListViewItem* item ) const
880 {
881   SUIT_DataObject* obj = 0;
882
883   if ( item && item->rtti() == OB_ListItem::RTTI() )
884     obj = ((OB_ListItem*)item)->dataObject();
885   else if ( item && item->rtti() == OB_CheckListItem::RTTI() )
886     obj = ((OB_CheckListItem*)item)->dataObject();
887
888   return obj;
889 }
890
891 QListViewItem* OB_Browser::listViewItem( const SUIT_DataObject* obj ) const
892 {
893   QListViewItem* item = 0;
894
895   if ( myItems.contains( (SUIT_DataObject*)obj ) )
896     item = myItems[(SUIT_DataObject*)obj];
897
898   return item;
899 }
900
901 QListView* OB_Browser::listView() const
902 {
903   return myView;
904 }
905
906 void OB_Browser::removeReferences( QListViewItem* item )
907 {
908   if ( !item )
909     return;
910
911   SUIT_DataObject* obj = dataObject( item );
912   obj->disconnect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
913   myItems.remove( obj );
914
915   QListViewItem* i = item->firstChild();
916   while ( i )
917   {
918     removeReferences( i );
919     i = i->nextSibling();
920   }
921 }
922
923 void OB_Browser::createConnections( SUIT_DataObject* obj )
924 {
925   if ( !obj )
926     return;
927
928   DataObjectList childList;
929   obj->children( childList, true );
930
931   childList.prepend( obj );
932
933   for ( DataObjectListIterator it( childList ); it.current(); ++it )
934     it.current()->connect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
935 }
936
937 void OB_Browser::removeConnections( SUIT_DataObject* obj )
938 {
939   if ( !obj )
940     return;
941
942   DataObjectList childList;
943   obj->children( childList, true );
944
945   childList.prepend( obj );
946
947   for ( DataObjectListIterator it( childList ); it.current(); ++it )
948     it.current()->disconnect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
949 }
950
951 SUIT_DataObject* OB_Browser::storeState( DataObjectMap& selObjs, DataObjectMap& openObjs,
952                                          DataObjectKeyMap& selKeys, DataObjectKeyMap& openKeys,
953                                          DataObjectKey& curKey ) const
954 {
955   QListView* lv = listView();
956   if ( !lv )
957     return 0;
958
959   SUIT_DataObject* curObj = dataObject( lv->currentItem() );
960
961   curKey = objectKey( curObj );
962
963   for ( QListViewItemIterator it( lv ); it.current(); ++it )
964   {
965     SUIT_DataObject* obj = dataObject( it.current() );
966     if ( !obj )
967       continue;
968
969     selObjs.insert( obj, lv->isSelected( it.current() ) );
970     openObjs.insert( obj, lv->isOpen( it.current() ) );
971     if ( lv->isSelected( it.current() ) )
972       selKeys.insert( objectKey( obj ), 0 );
973     if ( lv->isOpen( it.current() ) )
974       openKeys.insert( objectKey( obj ), 0 );
975   }
976
977   return curObj;
978 }
979
980 void OB_Browser::restoreState( const DataObjectMap& selObjs, const DataObjectMap& openObjs,
981                                const SUIT_DataObject* curObj, const DataObjectKeyMap& selKeys,
982                                const DataObjectKeyMap& openKeys, const DataObjectKey& curKey )
983 {
984   QListView* lv = listView();
985   if ( !lv )
986     return;
987
988   bool block = lv->signalsBlocked();
989   lv->blockSignals( true );
990
991   QListViewItem* curItem = 0;
992   for ( QListViewItemIterator it( lv ); it.current(); ++it )
993   {
994     QListViewItem* item = it.current();
995     SUIT_DataObject* obj = dataObject( item );
996
997     if ( !obj )
998       continue;
999
1000     DataObjectKey key = objectKey( obj );
1001
1002     if ( selObjs.contains( obj ) )
1003     {
1004       if ( selObjs[obj] && !lv->isSelected( item ) )
1005         lv->setSelected( item, true );
1006     }
1007     else if ( !key.isNull() && selKeys.contains( key ) && !lv->isSelected( item ) )
1008       lv->setSelected( item, true );
1009
1010     if ( openObjs.contains( obj ) )
1011     {
1012       bool parentOpen = true;
1013       if( item && item->parent() )
1014         parentOpen = item->parent()->isOpen();
1015         
1016       if ( openObjs[obj] && parentOpen )
1017         lv->setOpen( item, true );
1018     }
1019     else if ( !key.isNull() && openKeys.contains( key ) )
1020     {
1021       bool parentOpen = true;
1022       if( item && item->parent() )
1023         parentOpen = item->parent()->isOpen();
1024
1025       if( parentOpen )
1026         lv->setOpen( item, true );
1027     }
1028
1029     if ( !curItem && ( curObj == obj || ( !curKey.isNull() && curKey == key )) )
1030       curItem = item;
1031   }
1032
1033   if ( curItem )
1034     lv->setCurrentItem( curItem );
1035
1036   lv->blockSignals( block );
1037 }
1038
1039 OB_Browser::DataObjectKey OB_Browser::objectKey( QListViewItem* i ) const
1040 {
1041   return objectKey( dataObject( i ) );
1042 }
1043
1044 OB_Browser::DataObjectKey OB_Browser::objectKey( SUIT_DataObject* obj ) const
1045 {
1046   if ( !obj )
1047     return 0;
1048
1049   return DataObjectKey( obj->key() );
1050 }
1051
1052 void OB_Browser::keyPressEvent( QKeyEvent* e )
1053 {
1054   if ( e->key() == Qt::Key_F5 )
1055     updateTree( 0, false );
1056
1057   QFrame::keyPressEvent( e );
1058 }
1059
1060 void OB_Browser::onExpand()
1061 {
1062   DataObjectList selected;
1063   getSelected( selected );
1064   for ( DataObjectListIterator itr( selected ); itr.current(); ++itr )
1065     expand( listViewItem( itr.current() ) );
1066 }
1067
1068 void OB_Browser::onColumnVisible( int id )
1069 {
1070   setColumnShown( id, !isColumnVisible( id ) );
1071 }
1072
1073 void OB_Browser::onDestroyed( SUIT_DataObject* obj )
1074 {
1075   removeObject( obj );
1076 }
1077
1078 void OB_Browser::onDropped( QPtrList<QListViewItem> items, QListViewItem* item, int action )
1079 {
1080   SUIT_DataObject* obj = dataObject( item );
1081   if ( !obj )
1082     return;
1083
1084   DataObjectList lst;
1085   for ( QPtrListIterator<QListViewItem> it( items ); it.current(); ++it )
1086   {
1087     SUIT_DataObject* o = dataObject( it.current() );
1088     if ( o )
1089       lst.append( o );
1090   }
1091
1092   if ( !lst.isEmpty() )
1093     emit dropped( lst, obj, action );
1094 }
1095
1096 void OB_Browser::updateText()
1097 {
1098   if ( myColumnIds.isEmpty() )
1099     return;
1100
1101   QListView* lv = listView();
1102   if ( !lv )
1103     return;
1104
1105   for ( QListViewItemIterator it( lv ); it.current(); ++it )
1106   {
1107     SUIT_DataObject* obj = dataObject( it.current() );
1108     if ( !obj )
1109       continue;
1110
1111     for( QMap<int, int>::iterator itr = myColumnIds.begin(); itr != myColumnIds.end(); ++itr )
1112       it.current()->setText( itr.data(), obj->text( itr.key() ) );
1113   }
1114 }
1115
1116 void OB_Browser::updateText( QListViewItem* item )
1117 {
1118   SUIT_DataObject* obj = dataObject( item );
1119   if ( !obj )
1120     return;
1121
1122   for( QMap<int, int>::iterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
1123     item->setText( it.data(), obj->text( it.key() ) );
1124 }
1125
1126 bool OB_Browser::eventFilter( QObject* o, QEvent* e )
1127 {
1128   if ( o == myView && e->type() == QEvent::ContextMenu )
1129   {
1130     QContextMenuEvent* ce = (QContextMenuEvent*)e;
1131     if ( ce->reason() != QContextMenuEvent::Mouse )
1132       contextMenuRequest( ce );
1133     return true;
1134   }
1135   if ( o == myView->viewport() && e->type() == QEvent::MouseButtonRelease )
1136   {
1137     QMouseEvent* me = (QMouseEvent*)e;
1138     if ( me->button() == RightButton )
1139     {
1140       QContextMenuEvent ce( QContextMenuEvent::Mouse, me->pos(), me->globalPos(), me->state() );
1141       contextMenuRequest( &ce );
1142       return true;
1143     }
1144   }
1145
1146   return QFrame::eventFilter( o, e );
1147 }
1148
1149 void OB_Browser::contextMenuPopup( QPopupMenu* menu )
1150 {
1151 /*  QValueList<int> cols;
1152   for ( QMap<int, int>::ConstIterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
1153   {
1154     if ( appropriateColumn( it.key() ) )
1155       cols.append( it.key() );
1156   }
1157
1158   uint num = menu->count();
1159   menu->setCheckable( true );
1160   for ( QValueList<int>::const_iterator iter = cols.begin(); iter != cols.end(); ++iter )
1161   {
1162     QString name = columnTitle( *iter );
1163     if ( name.isEmpty() )
1164       continue;
1165
1166     int id = menu->insertItem( name, this, SLOT( onColumnVisible( int ) ) );
1167     menu->setItemChecked( id, isColumnVisible( *iter ) );
1168     menu->setItemParameter( id, *iter );
1169   }
1170   if ( menu->count() != num )
1171     menu->insertSeparator();*/
1172
1173   DataObjectList selected;
1174   getSelected( selected );
1175
1176   bool closed = false;
1177   for ( DataObjectListIterator itr( selected ); itr.current() && !closed; ++itr )
1178     closed = hasClosed( listViewItem( itr.current() ) );
1179
1180   if ( closed )
1181   {
1182     menu->insertItem( tr( "MEN_EXPAND_ALL" ), this, SLOT( onExpand() ) );
1183     menu->insertSeparator();
1184   }
1185 }
1186
1187 void OB_Browser::expand( QListViewItem* item )
1188 {
1189   if ( !item )
1190     return;
1191
1192   item->setOpen( true );
1193   for ( QListViewItem* child = item->firstChild(); child; child = child->nextSibling() )
1194     expand( child );
1195 }
1196
1197 bool OB_Browser::hasClosed( QListViewItem* item ) const
1198 {
1199   if ( !item )
1200     return false;
1201
1202   if ( item->childCount() && !item->isOpen() )
1203     return true;
1204
1205   bool has = false;
1206   for ( QListViewItem* child = item->firstChild(); child && !has; child = child->nextSibling() )
1207     has = hasClosed( child );
1208
1209   return has;
1210 }
1211
1212 void OB_Browser::removeObject( SUIT_DataObject* obj, const bool autoUpd )
1213 {
1214   if ( !obj )
1215     return;
1216
1217   // Removing list view items from <myItems> recursively for all children.
1218   // Otherwise, "delete item" line will destroy all item's children,
1219   // and <myItems> will contain invalid pointers (see ~QListViewItem() description in Qt docs)
1220   DataObjectList childList;
1221   obj->children( childList, true );
1222   for ( DataObjectListIterator it( childList ); it.current(); ++it )
1223   {
1224     it.current()->disconnect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
1225     myItems.remove( it.current() );
1226   }
1227
1228   QListViewItem* item = listViewItem( obj );
1229
1230   obj->disconnect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
1231   myItems.remove( obj );
1232
1233   if ( obj == myRoot )
1234   {
1235     // remove all child list view items
1236     setRootObject( 0 );
1237     return;
1238   }
1239
1240   if( !autoUpd )
1241     return;
1242
1243   if ( isAutoUpdate() )
1244   {
1245     SUIT_DataObject* pObj = item && item->parent() ? dataObject( item->parent() ) : 0;
1246     updateTree( pObj, false );
1247   }
1248
1249   delete item;
1250 }
1251
1252 void OB_Browser::autoOpenBranches()
1253 {
1254   int level = autoOpenLevel();
1255   QListView* lv = listView();
1256   if ( !lv || level < 1 )
1257     return;
1258
1259   QListViewItem* item = lv->firstChild();
1260   while ( item )
1261   {
1262     openBranch( item, level );
1263     item = item->nextSibling();
1264   }
1265 }
1266
1267 void OB_Browser::openBranch( QListViewItem* item, const int level )
1268 {
1269   if ( level < 1 )
1270     return;
1271
1272   while ( item )
1273   {
1274     item->setOpen( true );
1275     openBranch( item->firstChild(), level - 1 );
1276     item = item->nextSibling();
1277   }
1278 }
1279
1280 void OB_Browser::onDoubleClicked( QListViewItem* item )
1281 {
1282   if ( item )
1283     emit doubleClicked( dataObject( item ) );
1284 }
1285
1286 void OB_Browser::setModified()
1287 {
1288   myModifiedTime = clock();
1289 }
1290