Salome HOME
Join modifications from BR_Dev_For_4_0 tag V4_1_1.
[modules/gui.git] / src / ObjBrowser / OB_Browser.cxx
index 3866f6c7e31af305ba0bd6dce1112832ec175ada..41232b9a29e95585995e49a6b2f7886b1f6d2530 100755 (executable)
@@ -1,8 +1,30 @@
+// Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either 
+// version 2.1 of the License.
+// 
+// This library is distributed in the hope that it will be useful 
+// but WITHOUT ANY WARRANTY; without even the implied warranty of 
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public  
+// License along with this library; if not, write to the Free Software 
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
 #include "OB_Browser.h"
 
 #include "OB_Filter.h"
 #include "OB_ListItem.h"
 #include "OB_ListView.h"
+#include "OB_FindDlg.h"
+
+#include <SUIT_DataObjectIterator.h>
+#include <SUIT_TreeSync.h>
 
 #include <qcursor.h>
 #include <qlayout.h>
 #include <qwmatrix.h>
 #include <qlistview.h>
 #include <qpopupmenu.h>
+#include <qdatetime.h>
+
+#include <time.h>
 
 /*!
-    Class: OB_Browser::ToolTip
-    Descr: Tool tip for OB_Browser.
+  \class  OB_Browser::ToolTip
+  Tool tip for OB_Browser.
 */
 
 class OB_Browser::ToolTip : public QToolTip
@@ -29,22 +54,34 @@ private:
   OB_Browser* myBrowser;
 };
 
+/*!
+  Constructor
+*/
 OB_Browser::ToolTip::ToolTip( OB_Browser* b, QWidget* p )
 : QToolTip( p ),
 myBrowser( b )
 {
 }
 
+/*!
+  Destructor
+*/
 OB_Browser::ToolTip::~ToolTip()
 {
 }
 
+/*!
+  It is called when there is a possibility that a tool tip
+  should be shown and must decide whether there is a tool tip for the point
+  in the widget that this QToolTip object relates to.
+  \param pos - point co-ordinates
+*/
 void OB_Browser::ToolTip::maybeTip( const QPoint& pos )
 {
   if ( !parentWidget() || !myBrowser || !myBrowser->isShowToolTips() )
          return;
 
-  QListView* lv = myBrowser->getListView();
+  QListView* lv = myBrowser->listView();
 
   QListViewItem* item = lv->itemAt( pos );
   SUIT_DataObject* obj = myBrowser->dataObject( item );
@@ -61,95 +98,387 @@ void OB_Browser::ToolTip::maybeTip( const QPoint& pos )
   tip( aRect, aText );
 }
 
+
+typedef SUIT_DataObject*   ObjPtr;
+typedef OB_ListItem*       ItemPtr;
+
+/*!
+   \class  OB_BrowserSync
+   Auxiliary class for synchronizing tree of SUIT_DataObjects and list view items
+*/
+class OB_BrowserSync
+{
+public:
+  OB_BrowserSync( OB_Browser* );
+  bool     isEqual( const ObjPtr&, const ItemPtr& ) const;
+  ObjPtr   nullSrc() const;
+  ItemPtr  nullTrg() const;
+  ItemPtr  createItem( const ObjPtr&, const ItemPtr&, const ItemPtr&, const bool ) const;
+  void     updateItem( const ObjPtr& , const ItemPtr& ) const;
+  void     deleteItemWithChildren( const ItemPtr& ) const;
+  void     children( const ObjPtr&, QValueList<ObjPtr>& ) const;
+  void     children( const ItemPtr&, QValueList<ItemPtr>& ) const;
+  ItemPtr  parent( const ItemPtr& ) const;
+private:
+  bool     needUpdate( const ItemPtr& ) const;
+  OB_Browser*   myBrowser;
+};
+
+
+/*!
+  Constructor
+*/
+OB_BrowserSync::OB_BrowserSync( OB_Browser* ob )
+: myBrowser( ob )
+{
+}
+
 /*!
-    Class: OB_Browser
-    Descr: Hierarchical tree object browser.
+  \return true if item must be updated
+  \param item - item to be checked
 */
+bool OB_BrowserSync::needUpdate( const ItemPtr& item ) const
+{
+  bool update = false;
+  if ( item ) {
+    SUIT_DataObject* obj = item->dataObject();
+    if ( obj ) {
+      // 1. check text
+      update = ( item->text( 0 ) != obj->name() ) || myBrowser->needToUpdateTexts( item );
+
+      if ( !update ) { 
+       // 2. check pixmap (compare serialNumber()-s)
+       QPixmap objPix = obj->icon();
+       const QPixmap* itemPix = item->pixmap( 0 );
+       update = (  objPix.isNull() && (  itemPix && !itemPix->isNull() ) ) || 
+                ( !objPix.isNull() && ( !itemPix ||  itemPix->isNull() ) ); 
+       if ( !update && !objPix.isNull() && itemPix && !itemPix->isNull() ) {
+         int aIconW = objPix.width();
+         if( aIconW > 20 ) {
+           QWMatrix aM;
+           double aScale = 20.0 / aIconW;
+           aM.scale( aScale, aScale );
+           objPix = objPix.xForm( aM );
+         }
+         update = ( objPix.serialNumber() != itemPix->serialNumber() );
+       }
+      }
+    }
+  }
+  return update;
+}
 
+/*!
+  Updates item
+  \param p - item
+*/
+void OB_BrowserSync::updateItem( const ObjPtr& o, const ItemPtr& p ) const
+{
+  if ( p && needUpdate( p ) ) { 
+    //    printf( "--- needUpdate for %s = true ---\n", p->text( 0 ).latin1() );
+    myBrowser->updateText( p );
+    p->update();
+  }
+  if( o && myBrowser->getUpdater() )
+    {
+      myBrowser->getUpdater()->update( o, p );
+    }
+}
+
+/*!
+  Creates item by SUIT object
+  \param src - corresponding SUIT object
+  \param parent - parent for item
+  \param after - previous sibling for item
+  \param prepend - item must be added to start of children list
+*/
+ItemPtr OB_BrowserSync::createItem( const ObjPtr& src,
+                                   const ItemPtr& parent, const ItemPtr& after,
+                                   const bool prepend ) const
+{
+  ItemPtr i = myBrowser ? dynamic_cast<ItemPtr>( myBrowser->createItem( src, parent, after, prepend ) ) : 0;
+  if( i )
+    i->setOpen( src->isOpen() );
+  return i;
+}
+
+/*!
+  Deletes object with all children
+  \param i - item
+*/
+void OB_BrowserSync::deleteItemWithChildren( const ItemPtr& i ) const
+{
+  if( myBrowser && myBrowser->myItems.contains( i->dataObject() ) )
+  {
+    myBrowser->removeReferences( i );
+    delete i;
+  }
+}
+
+/*!
+  \return true if objects correspond each other at all
+  \param p - suit object
+  \param q - object browser item
+*/
+bool OB_BrowserSync::isEqual( const ObjPtr& p, const ItemPtr& q ) const
+{
+  bool isRoot = p==myBrowser->getRootObject() && !q,
+       isEq = p && q && q->dataObject()==p;
+  return isRoot || ( !p && !q ) || isEq;
+}
+
+/*!
+  \return null suit object
+*/
+ObjPtr OB_BrowserSync::nullSrc() const
+{
+  return 0;
+}
+
+/*!
+  \return null item
+*/
+ItemPtr OB_BrowserSync::nullTrg() const
+{
+  return 0;
+}
+
+/*!
+  Fills list with children of SUIT object
+  \param p - SUIT object
+  \param ch - list to be filled
+*/
+void OB_BrowserSync::children( const ObjPtr& p, QValueList<ObjPtr>& ch ) const
+{
+  DataObjectList l;
+  if( p )
+  {
+    p->children( l );
+    ch.clear();
+    for( SUIT_DataObject* o = l.first(); o; o = l.next() )
+      ch.append( o );
+  }
+}
+
+/*!
+  Fills list with children of item
+  \param p - item
+  \param ch - list to be filled
+*/
+void OB_BrowserSync::children( const ItemPtr& p, QValueList<ItemPtr>& ch ) const
+{
+  for( QListViewItem* item = p ? p->firstChild() : myBrowser->listView()->firstChild(); item; item = item->nextSibling() )
+  {
+    ItemPtr p = dynamic_cast<ItemPtr>( item );
+    if( p )
+      ch.append( p );
+  }
+}
+
+/*!
+  \return parent of item
+  \param p - item
+*/
+ItemPtr OB_BrowserSync::parent( const ItemPtr& p ) const
+{
+  return p ? dynamic_cast<ItemPtr>( p->parent() ) : 0;
+}
+
+
+/*!
+  Constructor
+*/
 OB_Browser::OB_Browser( QWidget* parent, SUIT_DataObject* root )
 : QFrame( parent ),
 
 myRoot( 0 ),
 myTooltip( 0 ),
+myUpdater( 0 ),
+myAutoOpenLevel( 0 ),
 myAutoUpdate( false ),
 myAutoDelObjs( false ),
 myRootDecorated( true )
 {
-  myView = new OB_ListView( this );
-  myView->addColumn( "Data" );
+  myView = new OB_ListView( QtxListView::HeaderAuto, this );
+  myView->setAppropriate( myView->addColumn( "Data" ), false );
   myView->setSorting( -1 );
   myView->setRootIsDecorated( true );
   myView->setSelectionMode( QListView::Extended );
   myView->installEventFilter( this );
+  myView->viewport()->installEventFilter( this );
+
+  myFindDlg = new OB_FindDlg( this );
+  myFindDlg->hide();
 
   QVBoxLayout* main = new QVBoxLayout( this );
-  main->addWidget( myView );
-  
+  main->addWidget( myView, 1 );
+  main->addWidget( myFindDlg, 0 );
+
   myShowToolTips = true;
   myTooltip = new ToolTip( this, myView->viewport() );
 
   connect( myView, SIGNAL( dropped( QPtrList<QListViewItem>, QListViewItem*, int ) ),
            this, SLOT( onDropped( QPtrList<QListViewItem>, QListViewItem*, int ) ) );
   connect( myView, SIGNAL( selectionChanged() ), this, SIGNAL( selectionChanged() ) );
+  connect( myView, SIGNAL( doubleClicked( QListViewItem* ) ),
+           this, SLOT( onDoubleClicked( QListViewItem* ) ) );
 
   setRootObject( root );
+
+  setModified();
 }
 
+/*!
+  Destructor
+*/
 OB_Browser::~OB_Browser()
 {
   myItems.clear();
   delete myTooltip;
+  setUpdater( 0 );
 }
 
+/*!
+  \return true if root is decorated by +
+*/
 bool OB_Browser::rootIsDecorated() const
 {
   return myRootDecorated;
 }
 
+/*!
+  Sets state "root is recorated"
+  \param decor - new value of state
+*/
 void OB_Browser::setRootIsDecorated( const bool decor )
 {
   if ( decor == rootIsDecorated() ) 
     return;
 
   myRootDecorated = decor;
-  updateTree();
+  updateTree( 0, false );
+}
+
+/*!
+  \return number of levels to be auto opened on update tree
+*/
+int OB_Browser::autoOpenLevel() const
+{
+  return myAutoOpenLevel;
+}
+
+/*!
+  Changes number of levels to be auto opened on update tree
+  \param level - new number of levels
+*/
+void OB_Browser::setAutoOpenLevel( const int level )
+{
+  if ( myAutoOpenLevel == level )
+    return;
+
+  myAutoOpenLevel = level;
 }
 
+/*!
+  Opens branches from 1 to \alevels. If parameter value negative then autoOpenLevel() value will be used.
+  \sa autoOpenLevel()
+*/
+void OB_Browser::openLevels( const int levels )
+{
+  int level = levels < 0 ? autoOpenLevel() : levels;
+  QListView* lv = listView();
+  if ( !lv || level < 1 )
+    return;
+
+  QListViewItem* item = lv->firstChild();
+  while ( item )
+  {
+    openBranch( item, level );
+    item = item->nextSibling();
+  }
+}
+
+/*!
+  \return state "are tooltips shown"
+*/
 bool OB_Browser::isShowToolTips()
 {
   return myShowToolTips;
 }
 
+/*!
+  Sets new value of state "are tooltips shown"
+  \param theDisplay - new value
+*/
 void OB_Browser::setShowToolTips( const bool theDisplay )
 {
   myShowToolTips = theDisplay;
 }
 
+/*!
+  \return true if object browser automatically updates tree after SUIT object removing
+*/
 bool OB_Browser::isAutoUpdate() const
 {
   return myAutoUpdate;
 }
 
+/*!
+  Sets new value of "auto update": whether object browser automatically updates tree after SUIT object removing
+*/
 void OB_Browser::setAutoUpdate( const bool on )
 {
   myAutoUpdate = on;
 }
 
+/*!
+  \return true if object browser must delete old tree on setRootObject(), replaceTree()
+  \sa setRootObject(), replaceTree()
+*/
 bool OB_Browser::isAutoDeleteObjects() const
 {
   return myAutoDelObjs;
 }
 
+/*!
+  Sets whether object browser must delete old tree on setRootObject(), replaceTree()
+  \sa setRootObject(), replaceTree()
+*/
 void OB_Browser::setAutoDeleteObjects( const bool on )
 {
   myAutoDelObjs = on;
 }
 
+/*!
+  \return updater of browser
+*/
+OB_Updater* OB_Browser::getUpdater() const
+{
+  return myUpdater;
+}
+
+/*!
+  \sets new updater of browser
+*/
+void OB_Browser::setUpdater( OB_Updater* theUpdate )
+{
+  if( myUpdater )
+    delete myUpdater;
+  myUpdater = theUpdate;
+}
+
+/*!
+  \return root SUIT object of browser
+*/
 SUIT_DataObject* OB_Browser::getRootObject() const
 {
   return myRoot;
 }
 
+/*!
+  Sets new root SUIT object of browser
+  \param theRoot - new root object
+*/
 void OB_Browser::setRootObject( SUIT_DataObject* theRoot )
 {
   DataObjectKey curKey;
@@ -162,6 +491,7 @@ void OB_Browser::setRootObject( SUIT_DataObject* theRoot )
   if ( theRoot )
     curObj = storeState( selObjs, openObjs, selKeys, openKeys, curKey );
 
+  removeConnections( myRoot );
   if ( myRoot != theRoot && isAutoDeleteObjects() )
     delete myRoot;
 
@@ -171,30 +501,40 @@ void OB_Browser::setRootObject( SUIT_DataObject* theRoot )
 
   if ( myRoot )
     updateView( myRoot );
-  else if ( getListView() )
+  else if ( listView() )
   {
     myItems.clear();
-    getListView()->clear();
+    listView()->clear();
   }
 
   restoreState( selObjs, openObjs, curObj, selKeys, openKeys, curKey );
 
+  autoOpenBranches();
+
+  setModified();
+
   if ( selNum != numberOfSelected() )
     emit selectionChanged();
 }
 
+/*!
+  \return number of selected items
+*/
 int OB_Browser::numberOfSelected() const
 {
   int count = 0;
-  if ( getListView() )
+  if ( listView() )
   {
-    for ( QListViewItemIterator it( getListView() ); it.current(); ++it )
+    for ( QListViewItemIterator it( listView() ); it.current(); ++it )
       if ( it.current()->isSelected() ) 
         count++;
   }
   return count;
 }
 
+/*!
+  \return list of selected objects
+*/
 DataObjectList OB_Browser::getSelected() const
 {
   DataObjectList lst;
@@ -202,24 +542,33 @@ DataObjectList OB_Browser::getSelected() const
   return lst;
 }
 
+/*!
+  Fills list with selected objects
+*/
 void OB_Browser::getSelected( DataObjectList& theObjList ) const
 {
   theObjList.clear();
 
-  if ( !getListView() )
+  if ( !listView() )
     return;
 
-  for ( QListViewItemIterator it( getListView() ); it.current(); ++it )
+  for ( QListViewItemIterator it( listView() ); it.current(); ++it )
   {
     if ( it.current()->isSelected() ) 
     {
       SUIT_DataObject* obj = dataObject( it.current() );
       if ( obj )
-             theObjList.append( obj );
+       theObjList.append( obj );
     }
   }
 }
 
+/*!
+  Sets selected object
+  \param theObject - new selected object
+  \param append - if it is true, then other selected objects are left as selected,
+  otherwise only 'theObject' will be selected
+*/
 void OB_Browser::setSelected( const SUIT_DataObject* theObject, const bool append )
 {
   DataObjectList lst;
@@ -227,9 +576,15 @@ void OB_Browser::setSelected( const SUIT_DataObject* theObject, const bool appen
   setSelected( lst, append );
 }
 
+/*!
+  Sets selected objects
+  \param theObjLst - new selected objects
+  \param append - if it is true, then other selected objects are left as selected,
+  otherwise only 'theObjLst' will be selected
+*/
 void OB_Browser::setSelected( const DataObjectList& theObjLst, const bool append )
 {
-  QListView* lv = getListView();
+  QListView* lv = listView();
 
   if ( !lv )
     return;
@@ -286,99 +641,289 @@ void OB_Browser::setSelected( const DataObjectList& theObjLst, const bool append
   }
 }
 
+/*!
+  \return true if item corresponding to object is opened
+  \param theObject - object to be checked
+*/
 bool OB_Browser::isOpen( SUIT_DataObject* theObject ) const
 {
   bool res = false;
-  if ( getListView() )
-    res = getListView()->isOpen( listViewItem( theObject ) );
+  if ( listView() )
+    res = listView()->isOpen( listViewItem( theObject ) );
   return res;
 }
 
+/*!
+  Sets opened state of item
+  \param theObject - object corresponding to item
+  \param theOpen - new opened state
+*/
 void OB_Browser::setOpen( SUIT_DataObject* theObject, const bool theOpen )
 {
-  if ( getListView() )
-    getListView()->setOpen( listViewItem( theObject ), theOpen );
+  if ( listView() )
+    listView()->setOpen( listViewItem( theObject ), theOpen );
 }
 
+/*!
+  \return SUIT object correspondint to item at position 'pos'
+  \param pos - position
+*/
 SUIT_DataObject* OB_Browser::dataObjectAt( const QPoint& pos ) const
 {
   SUIT_DataObject* obj = 0;
 
-  QListView* lv = getListView();
+  QListView* lv = listView();
   if ( lv )
     obj = dataObject( lv->itemAt( pos ) );
 
   return obj;
 }
 
+/*!
+  \return filter of list view
+*/
 OB_Filter* OB_Browser::filter() const
 {
   return myView->filter();
 }
 
+/*!
+  Changes filter of list view
+  \param f - new filter
+*/
 void OB_Browser::setFilter( OB_Filter* f )
 {
   myView->setFilter( f );
 }
 
-int OB_Browser::addColumn( const QString & label, int width, int index )
+/*!
+  Adds new column to list view
+  \param label - title of column
+  \param id - id of column
+  \param width - width of column
+*/
+int OB_Browser::addColumn( const QString& label, const int id, const int width )
 {
-  int id = -1;
-  if ( !myView )
-    return id;
-  if ( index != -1 && myColumnIds.contains( index ) )
-    return id; // can not reuse index
-
-  int trueId = index;
-  id = myView->addColumn( label, width );
-  if ( trueId == -1 )
-    trueId = id;
-  myColumnIds.insert( trueId, id );
-  updateText();
-
-  return trueId;
+  return addColumn( QIconSet(), label, id, width );
 }
 
-int OB_Browser::addColumn( const QIconSet & iconset, const QString & label, int width, int index )
+/*!
+  Adds new column to list view
+  \param icon - icon of column
+  \param label - title of column
+  \param id - id of column
+  \param width - width of column
+*/
+int OB_Browser::addColumn( const QIconSet& icon, const QString& label, const int id, const int width )
 {
-  int id = -1;
-  if ( !myView )
-    return id;
-  if ( index != -1 && myColumnIds.contains( index ) )
-    return id; // can not reuse index
+  QListView* lv = listView();
+  if ( !lv )
+    return -1;
 
-  int trueId = index;
-  id = myView->addColumn( iconset, label, width );
-  if ( trueId == -1 )
-    trueId = id;
-  myColumnIds.insert( trueId, id );
+  int theId = id;
+  if ( theId < 0 )
+  {
+    while ( myColumnIds.contains( theId ) )
+      theId++;
+  }
+
+  if ( myColumnIds.contains( theId ) )
+    return -1; // can not reuse id
+
+  int sec = -1;
+  if ( icon.isNull() )
+    sec = lv->addColumn( label, width );
+  else
+    sec = lv->addColumn( icon, label, width );
+
+  if ( sec == -1 )
+    return -1;
+
+  myColumnIds.insert( theId, sec );
   updateText();
 
-  return trueId;
+  return theId;
 }
 
-void OB_Browser::removeColumn( int index )
+/*!
+  Removes column
+  \param id - id of column
+*/
+void OB_Browser::removeColumn( const int id )
 {
-  if ( !myView || !myColumnIds.contains( index ) )
+  QListView* lv = listView();
+  if ( !lv || !myColumnIds.contains( id ) )
     return;
 
-  int id = myColumnIds[ index ];
-  myView->removeColumn( id );
+  int sec = myColumnIds[id];
+  lv->removeColumn( sec );
 
   // update map of column indeces
-  myColumnIds.remove( index );
+  myColumnIds.remove( id );
   for ( QMap<int, int>::iterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
   {
-    if ( it.key() > index )
+    if ( it.key() > id )
       it.data()--;
   }
   updateText();
 }
 
-void OB_Browser::updateTree( SUIT_DataObject* o )
+/*!
+  Sets title of first column (name column)
+  \param label - new title
+*/
+void OB_Browser::setNameTitle( const QString& label )
 {
-  SUIT_DataObject* obj = o ? o : getRootObject();
-  if ( !obj )
+  setNameTitle( QIconSet(), label );
+}
+
+/*!
+  Sets title and icon of first column (name column)
+  \param icon - new icon
+  \param label - new title
+*/
+void OB_Browser::setNameTitle( const QIconSet& icon, const QString& label )
+{
+  QListView* lv = listView();
+  if ( !lv )
+    return;
+
+  if ( icon.isNull() )
+    lv->setColumnText( 0, label );
+  else
+    lv->setColumnText( 0, icon, label );
+}
+
+/*!
+  Sets title of column
+  \param id - column id
+  \param label - new column title
+*/
+void OB_Browser::setColumnTitle( const int id, const QString& label )
+{
+  setColumnTitle( id, QIconSet(), label );
+}
+
+/*!
+  Sets title and icon of column
+  \param id - column id
+  \param icon - new column icon
+  \param label - new column title
+*/
+void OB_Browser::setColumnTitle( const int id, const QIconSet& icon, const QString& label )
+{
+  QListView* lv = listView();
+  if ( !lv || !myColumnIds.contains( id ) )
+    return;
+
+  if ( icon.isNull() )
+    lv->setColumnText( myColumnIds[id], label );
+  else
+    lv->setColumnText( myColumnIds[id], icon, label );
+}
+
+/*!
+  \return title of first column (name column)
+*/
+QString OB_Browser::nameTitle() const
+{
+  return myView->columnText( 0 );
+}
+
+/*!
+  \return title of first column (name column)
+  \param id - column id
+*/
+QString OB_Browser::columnTitle( const int id ) const
+{
+  QString txt;
+  if ( myColumnIds.contains( id ) )
+    txt = myView->columnText( myColumnIds[id] );
+  return txt;
+}
+
+/*!
+  \return true if column is visible
+  \param id - column id
+*/
+bool OB_Browser::isColumnVisible( const int id ) const
+{
+  return myColumnIds.contains( id ) && myView->isShown( myColumnIds[id] );
+}
+
+/*!
+  Sets visibility of column
+  \param id - column id
+  \param on - new visibility state
+*/
+void OB_Browser::setColumnShown( const int id, const bool on )
+{
+  if ( !myColumnIds.contains( id ) )
+    return;
+
+  myView->setShown( myColumnIds[id], on );
+  if( !on )
+    myView->setColumnWidthMode( myColumnIds[id], QListView::Manual );
+}
+
+/*!
+  Sets global width mode
+  \param mode - new width mode
+*/
+void OB_Browser::setWidthMode( QListView::WidthMode mode )
+{
+  for ( int i = 0, n = myView->columns(); i < n; i++ )
+    if( mode!=QListView::Maximum || myView->columnWidth( i )>0 )
+      myView->setColumnWidthMode( i, mode );
+}
+
+/*!
+  \return list of columns ids
+*/
+QValueList<int> OB_Browser::columns() const
+{
+  QValueList<int> lst;
+  for ( QMap<int, int>::ConstIterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
+    lst.append( it.key() );
+  return lst;
+}
+
+/*!
+  \return true if it is possible to show/hide column by popup
+  \param id - column id
+*/
+bool OB_Browser::appropriateColumn( const int id ) const
+{
+  bool res = false;
+  if ( myColumnIds.contains( id ) )
+    res = myView->appropriate( myColumnIds[id] );
+  return res;
+}
+
+/*!
+  Sets "appropriate state": is it possible to show/hide column by popup
+  \param id - column id
+  \param on - new state
+*/
+void OB_Browser::setAppropriateColumn( const int id, const bool on )
+{
+  if ( !myColumnIds.contains( id ) )
+    return;
+
+  myView->setAppropriate( myColumnIds[id], on );
+}
+
+/*!
+  Updates tree
+  \param obj - start object
+  \param autoOpen - to open automatically branches of autoOpenLevel()
+  \sa autoOpenLevel()
+*/
+void OB_Browser::updateTree( SUIT_DataObject* obj, const bool autoOpen )
+{
+//  QTime t1 = QTime::currentTime();
+
+  if ( !obj && !(obj = getRootObject()) )
     return;
 
   DataObjectKey curKey;
@@ -389,18 +934,28 @@ void OB_Browser::updateTree( SUIT_DataObject* o )
 
   SUIT_DataObject* curObj = storeState( selObjs, openObjs, selKeys, openKeys, curKey );
 
-  createConnections( obj );
   updateView( obj );
 
   restoreState( selObjs, openObjs, curObj, selKeys, openKeys, curKey );
 
+  if ( autoOpen )
+    autoOpenBranches();
+
+  setModified();
+
   if ( selNum != numberOfSelected() )
     emit selectionChanged();
+
+//  QTime t2 = QTime::currentTime();
+//  qDebug( QString( "update tree time = %1 msecs" ).arg( t1.msecsTo( t2 ) ) );
 }
 
+/*!
+  Replaces part of tree starting at object 'src' by tree starting at object 'trg'
+*/
 void OB_Browser::replaceTree( SUIT_DataObject* src, SUIT_DataObject* trg )
 {
-  if ( !src || !trg || src->root() != getRootObject() )
+  if ( !src || !trg || src == trg || src->root() != getRootObject() )
     return;
 
   DataObjectKey curKey;
@@ -416,7 +971,8 @@ void OB_Browser::replaceTree( SUIT_DataObject* src, SUIT_DataObject* trg )
 
   src->setParent( 0 );
 
-  if ( src != trg && isAutoDeleteObjects() )
+  removeConnections( src );
+  if ( isAutoDeleteObjects() )
     delete src;
 
   if ( parent && pos != -1 )
@@ -424,92 +980,58 @@ void OB_Browser::replaceTree( SUIT_DataObject* src, SUIT_DataObject* trg )
 
   trg->setParent( parent );
 
-  createConnections( trg );
   updateView( trg );
+  createConnections( trg );
 
   restoreState( selObjs, openObjs, curObj, selKeys, openKeys, curKey );
 
+  setModified();
+
   if ( selNum != numberOfSelected() )
     emit selectionChanged();
 }
 
-void OB_Browser::updateView( const SUIT_DataObject* theStartObj )
+/*!
+  Updates view
+  \param startObj - start object
+*/
+void OB_Browser::updateView( SUIT_DataObject* startObj )
 {
-  QListView* lv = getListView();
+  QListView* lv = listView();
   if ( !lv )
     return;
 
-  if ( !theStartObj || theStartObj->root() != getRootObject() )
+  if ( !startObj || startObj->root() != getRootObject() )
     return;
 
-  QListViewItem* after = 0;
-  QListViewItem* parent = 0;
-  QListViewItem* startItem = listViewItem( theStartObj );
-
-  if ( theStartObj->parent() )
-    parent = listViewItem( theStartObj->parent() );
-
-  QListViewItem* prv = 0;
-  QListViewItem* cur = parent ? parent->firstChild() : lv->firstChild();
-  while ( !after && cur )
-  {
-    if ( cur == startItem )
-      after = prv;
-
-    prv = cur;
-    cur = cur->nextSibling();
-  }
+  //qDebug( "updateView:" );
+  //startObj->dump();
 
-  QPtrList<QListViewItem> delList;
-  if ( !startItem && theStartObj == getRootObject() )
+  if ( startObj == myRoot )
   {
-    for ( QListViewItem* item = lv->firstChild(); item; item = item->nextSibling() )
-      delList.append( item );
+    OB_BrowserSync sync( this );
+    synchronize<ObjPtr,ItemPtr,OB_BrowserSync>( myRoot, 0, sync );
   }
   else
-    delList.append( startItem );
-
-  for ( QPtrListIterator<QListViewItem> it( delList ); it.current(); ++it )
-  {
-    removeReferences( it.current() );
-    delete it.current();
-  }
-
-  // for myRoot object, if myShowRoot==false, then creating multiple top-level QListViewItem-s
-  // (which will correspond to myRoot's children = Modules).  
-  if ( rootIsDecorated() && theStartObj == myRoot )
   {
-    DataObjectList lst;
-    theStartObj->children( lst );
-    DataObjectListIterator it ( lst );
-    // iterating backward to preserve the order of elements in the tree
-    for ( it.toLast(); it.current(); --it )
-      createTree( it.current(), 0, 0 );
+    OB_BrowserSync sync( this );
+    OB_ListItem* startItem = dynamic_cast<OB_ListItem*>( listViewItem( startObj ) );
+    synchronize<ObjPtr,ItemPtr,OB_BrowserSync>( startObj, startItem, sync );
   }
-  else
-    createTree( theStartObj, parent, after );
 }
 
-QListViewItem* OB_Browser::createTree( const SUIT_DataObject* obj,
-                                          QListViewItem* parent, QListViewItem* after )
-{
-  if ( !obj )
-    return 0;
-  
-  QListViewItem* item = createItem( obj, parent, after );
-
-  DataObjectList lst;
-  obj->children( lst );
-  for ( DataObjectListIterator it ( lst ); it.current(); ++it )
-    createTree( it.current(), item );
-
-  return item;
-}
-
-QListViewItem* OB_Browser::createItem( const SUIT_DataObject* o,
-                                       QListViewItem* parent, QListViewItem* after )
+/*!
+  Creates new list item
+  \return new item
+  \param o - corresponding SUIT object
+  \param parent - parent item
+  \param after - item after that new item must be added
+  \param prepend - new item must be added as first
+*/
+QListViewItem* OB_Browser::createItem( const SUIT_DataObject* o, QListViewItem* parent,
+                                      QListViewItem* after, const bool prepend )
 {
-  QListView* lv = getListView();
+  QListView* lv = listView();
 
   if ( !lv || !o )
     return 0;
@@ -531,51 +1053,83 @@ QListViewItem* OB_Browser::createItem( const SUIT_DataObject* o,
 
   if ( parent )
   {
-    if ( parent->childCount() && !after )
+    if ( after ) 
     {
-      after = parent->firstChild();
-      while ( after->nextSibling() )
-        after = after->nextSibling();
+      if ( type == -1 )
+       item = new OB_ListItem( obj, parent, after );
+      else
+       item = new OB_CheckListItem( obj, parent, after, (QCheckListItem::Type)type );
     }
-
-    if ( after )
+    else if ( prepend )
     {
       if ( type == -1 )
-        item = new OB_ListItem( obj, parent, after );
+       item = new OB_ListItem( obj, parent );
       else
-        item = new OB_CheckListItem( obj, parent, after, (QCheckListItem::Type)type );
+       item = new OB_CheckListItem( obj, parent,  (QCheckListItem::Type)type );
     }
-    else
+    else // append
     {
+      after = parent->firstChild();
+      while ( after && after->nextSibling() )
+       after = after->nextSibling();
       if ( type == -1 )
-        item = new OB_ListItem( obj, parent );
+       item = new OB_ListItem( obj, parent, after );
       else
-        item = new OB_CheckListItem( obj, parent,  (QCheckListItem::Type)type );
+       item = new OB_CheckListItem( obj, parent, after, (QCheckListItem::Type)type );
     }
   }
-  else // ROOT item
+  else
   {
-    if ( type == -1 )
-      item = new OB_ListItem( obj, lv );
-    else
-      item = new OB_CheckListItem( obj, lv,  (QCheckListItem::Type)type );
+    if ( after ) 
+    {
+      if ( type == -1 )
+       item = new OB_ListItem( obj, lv, after );
+      else
+       item = new OB_CheckListItem( obj, lv, after, (QCheckListItem::Type)type );
+    }
+    else if ( prepend )
+    {
+      if ( type == -1 )
+       item = new OB_ListItem( obj, lv );
+      else
+       item = new OB_CheckListItem( obj, lv,  (QCheckListItem::Type)type );
+    }
+    else // append
+    {
+      after = lv->firstChild();
+      while ( after && after->nextSibling() )
+       after = after->nextSibling();
+      if ( type == -1 )
+       item = new OB_ListItem( obj, lv, after );
+      else
+       item = new OB_CheckListItem( obj, lv, after, (QCheckListItem::Type)type );
+    }
   }
 
   myItems.insert( obj, item );
+  obj->connect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
+  updateText( item );
 
   return item;
 }
 
+/*!
+  Adjusts width by root item
+*/
 void OB_Browser::adjustWidth()
 {
-  if ( !getListView() )
+  if ( !listView() )
     return;
 
-  getListView()->setColumnWidth( 0, 0 );
-  if ( getListView()->firstChild() )
-    adjustWidth( getListView()->firstChild() );
+  listView()->setColumnWidth( 0, 0 );
+  if ( listView()->firstChild() )
+    adjustWidth( listView()->firstChild() );
 }
 
+/*!
+  Adjusts width by item
+  \param item
+*/
 void OB_Browser::adjustWidth( QListViewItem* item )
 {
   while ( item )
@@ -587,6 +1141,10 @@ void OB_Browser::adjustWidth( QListViewItem* item )
   }
 }
 
+/*!
+  \return SUIT object corresponding to item
+  \param item
+*/
 SUIT_DataObject* OB_Browser::dataObject( const QListViewItem* item ) const
 {
   SUIT_DataObject* obj = 0;
@@ -599,6 +1157,10 @@ SUIT_DataObject* OB_Browser::dataObject( const QListViewItem* item ) const
   return obj;
 }
 
+/*!
+  \return item corresponding to SUIT object
+  \param obj - SUIT object
+*/
 QListViewItem* OB_Browser::listViewItem( const SUIT_DataObject* obj ) const
 {
   QListViewItem* item = 0;
@@ -609,17 +1171,24 @@ QListViewItem* OB_Browser::listViewItem( const SUIT_DataObject* obj ) const
   return item;
 }
 
-QListView* OB_Browser::getListView() const
+/*!
+  \return list view of object browser
+*/
+QListView* OB_Browser::listView() const
 {
   return myView;
 }
 
+/*!
+  \remove all items referencing current (through data objects)
+*/
 void OB_Browser::removeReferences( QListViewItem* item )
 {
   if ( !item )
     return;
 
   SUIT_DataObject* obj = dataObject( item );
+  obj->disconnect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
   myItems.remove( obj );
 
   QListViewItem* i = item->firstChild();
@@ -630,6 +1199,9 @@ void OB_Browser::removeReferences( QListViewItem* item )
   }
 }
 
+/*!
+  Connects all children to SLOT onDestroyed
+*/
 void OB_Browser::createConnections( SUIT_DataObject* obj )
 {
   if ( !obj )
@@ -644,11 +1216,35 @@ void OB_Browser::createConnections( SUIT_DataObject* obj )
     it.current()->connect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
 }
 
+/*!
+  Disconnects all children from SLOT onDestroyed
+*/
+void OB_Browser::removeConnections( SUIT_DataObject* obj )
+{
+  if ( !obj )
+    return;
+
+  DataObjectList childList;
+  obj->children( childList, true );
+
+  childList.prepend( obj );
+
+  for ( DataObjectListIterator it( childList ); it.current(); ++it )
+    it.current()->disconnect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
+}
+
+/*!
+  Stores states (opened, selected) of current tree items
+  \return current item
+  \param selObjs, selKeys - maps of selected objects
+  \param openObjs, openKeys - maps of opened objects
+  \param curKey - map of current objects
+*/
 SUIT_DataObject* OB_Browser::storeState( DataObjectMap& selObjs, DataObjectMap& openObjs,
                                          DataObjectKeyMap& selKeys, DataObjectKeyMap& openKeys,
                                          DataObjectKey& curKey ) const
 {
-  QListView* lv = getListView();
+  QListView* lv = listView();
   if ( !lv )
     return 0;
 
@@ -673,11 +1269,17 @@ SUIT_DataObject* OB_Browser::storeState( DataObjectMap& selObjs, DataObjectMap&
   return curObj;
 }
 
+/*!
+  Restores states (opened, selected) of current tree items
+  \param selObjs, selKeys - maps of selected objects
+  \param openObjs, openKeys - maps of opened objects
+  \param curKey - map of current objects
+*/
 void OB_Browser::restoreState( const DataObjectMap& selObjs, const DataObjectMap& openObjs,
                                const SUIT_DataObject* curObj, const DataObjectKeyMap& selKeys,
                                const DataObjectKeyMap& openKeys, const DataObjectKey& curKey )
 {
-  QListView* lv = getListView();
+  QListView* lv = listView();
   if ( !lv )
     return;
 
@@ -705,11 +1307,22 @@ void OB_Browser::restoreState( const DataObjectMap& selObjs, const DataObjectMap
 
     if ( openObjs.contains( obj ) )
     {
-      if ( openObjs[obj] )
+      bool parentOpen = true;
+      if( item && item->parent() )
+       parentOpen = item->parent()->isOpen();
+       
+      if ( openObjs[obj] && parentOpen )
         lv->setOpen( item, true );
     }
     else if ( !key.isNull() && openKeys.contains( key ) )
-      lv->setOpen( item, true );
+    {
+      bool parentOpen = true;
+      if( item && item->parent() )
+       parentOpen = item->parent()->isOpen();
+
+      if( parentOpen )
+       lv->setOpen( item, true );
+    }
 
     if ( !curItem && ( curObj == obj || ( !curKey.isNull() && curKey == key )) )
       curItem = item;
@@ -721,11 +1334,17 @@ void OB_Browser::restoreState( const DataObjectMap& selObjs, const DataObjectMap
   lv->blockSignals( block );
 }
 
+/*!
+  Creates object key by tree item
+*/
 OB_Browser::DataObjectKey OB_Browser::objectKey( QListViewItem* i ) const
 {
   return objectKey( dataObject( i ) );
 }
 
+/*!
+  Creates object key by SUIT object
+*/
 OB_Browser::DataObjectKey OB_Browser::objectKey( SUIT_DataObject* obj ) const
 {
   if ( !obj )
@@ -734,23 +1353,20 @@ OB_Browser::DataObjectKey OB_Browser::objectKey( SUIT_DataObject* obj ) const
   return DataObjectKey( obj->key() );
 }
 
+/*!
+  Custom key press event handler, updates tree by F5
+*/
 void OB_Browser::keyPressEvent( QKeyEvent* e )
 {
   if ( e->key() == Qt::Key_F5 )
-    updateTree();
-
-  if ( ( e->key() == Qt::Key_Plus || e->key() == Qt::Key_Minus ) &&
-       e->state() & ControlButton && getListView() )
-  {
-    bool isOpen = e->key() == Qt::Key_Plus;
-    for ( QListViewItemIterator it( getListView() ); it.current(); ++it )
-      if ( it.current()->childCount() )
-        it.current()->setOpen( isOpen );
-  }
+    updateTree( 0, false );
 
   QFrame::keyPressEvent( e );
 }
 
+/*!
+  SLOT: called if action "Expand all" is activated
+*/
 void OB_Browser::onExpand()
 {
   DataObjectList selected;
@@ -759,40 +1375,28 @@ void OB_Browser::onExpand()
     expand( listViewItem( itr.current() ) );
 }
 
-void OB_Browser::onRefresh()
+/*!
+  SLOT: called if action "Show/hide column" is activated by popup
+*/
+void OB_Browser::onColumnVisible( int id )
 {
-  updateTree();
+  setColumnShown( id, !isColumnVisible( id ) );
 }
 
+/*!
+  SLOT: called if SUIT object is destroyed
+*/
 void OB_Browser::onDestroyed( SUIT_DataObject* obj )
 {
-  if ( !obj )
-    return;
-
-  // Removing list view items from <myItems> recursively for all children.
-  // Otherwise, "delete item" line will destroy all item's children,
-  // and <myItems> will contain invalid pointers (see ~QListViewItem() description in Qt docs)
-  DataObjectList childList;
-  obj->children( childList );
-  for ( DataObjectListIterator it( childList ); it.current(); ++it )
-    onDestroyed( it.current() );
-
-  QListViewItem* item = listViewItem( obj );
-
-  myItems.remove( obj );
-
-  if ( obj == myRoot )
-    myRoot = 0;
-
-  if ( isAutoUpdate() )
-  {
-    SUIT_DataObject* pObj = item && item->parent() ? dataObject( item->parent() ) : 0;
-    updateTree( pObj );
-  }
-  else
-    delete item;
+  removeObject( obj );
 }
 
+/*!
+  SLOT: called on finish of drag-n-drop operation
+  \param items - dragged items
+  \param item - destination (item on that they were dropped)
+  \param action - QDropEvent::Action
+*/
 void OB_Browser::onDropped( QPtrList<QListViewItem> items, QListViewItem* item, int action )
 {
   SUIT_DataObject* obj = dataObject( item );
@@ -811,40 +1415,113 @@ void OB_Browser::onDropped( QPtrList<QListViewItem> items, QListViewItem* item,
     emit dropped( lst, obj, action );
 }
 
+/*!
+  Updates texts of items
+*/
 void OB_Browser::updateText()
 {
-  if ( !myView )
+  if ( myColumnIds.isEmpty() )
+    return;
+
+  QListView* lv = listView();
+  if ( !lv )
     return;
-  
-  if ( myColumnIds.size() )
+
+  for ( QListViewItemIterator it( lv ); it.current(); ++it )
   {
-    QListViewItemIterator it( myView );
-    for ( ; it.current() != 0; ++it )
-    {
-      QListViewItem* item = it.current();
-      SUIT_DataObject* obj = dataObject( item );
-      if ( !item || !obj )
-        continue;
-      QMap<int, int>::iterator it = myColumnIds.begin();
-      for( ; it != myColumnIds.end(); ++it )
-        item->setText( it.data(), obj->text( it.key() ) );
-    }
+    SUIT_DataObject* obj = dataObject( it.current() );
+    if ( !obj )
+      continue;
+
+    for( QMap<int, int>::iterator itr = myColumnIds.begin(); itr != myColumnIds.end(); ++itr )
+      it.current()->setText( itr.data(), obj->text( itr.key() ) );
   }
-  updateView();
 }
 
-bool OB_Browser::eventFilter(QObject* watched, QEvent* e)
+/*!
+  \return true if item must be updated
+  \param item - item to be checked
+*/
+bool OB_Browser::needToUpdateTexts( QListViewItem* item ) const
+{
+  SUIT_DataObject* obj = dataObject( item );
+  if ( !obj )
+    return false;
+
+  for( QMap<int, int>::const_iterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
+    if( item->text( it.data() ) != obj->text( it.key() ) )
+      return true;
+  return false;
+}
+
+/*!
+  Updates texts of item
+  \param item - item to be updated
+*/
+void OB_Browser::updateText( QListViewItem* item )
 {
-  if ( watched == myView && e->type() == QEvent::ContextMenu )
+  SUIT_DataObject* obj = dataObject( item );
+  if ( !obj )
+    return;
+
+  for( QMap<int, int>::iterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
+    item->setText( it.data(), obj->text( it.key() ) );
+}
+
+/*!
+  Custom event filter
+*/
+bool OB_Browser::eventFilter( QObject* o, QEvent* e )
+{
+  if ( o == myView && e->type() == QEvent::ContextMenu )
   {
-    contextMenuRequest( (QContextMenuEvent*)e );
+    QContextMenuEvent* ce = (QContextMenuEvent*)e;
+    if ( ce->reason() != QContextMenuEvent::Mouse )
+      contextMenuRequest( ce );
     return true;
   }
-  return QFrame::eventFilter(watched, e);
+  if ( o == myView->viewport() && e->type() == QEvent::MouseButtonRelease )
+  {
+    QMouseEvent* me = (QMouseEvent*)e;
+    if ( me->button() == RightButton )
+    {
+      QContextMenuEvent ce( QContextMenuEvent::Mouse, me->pos(), me->globalPos(), me->state() );
+      contextMenuRequest( &ce );
+      return true;
+    }
+  }
+
+  return QFrame::eventFilter( o, e );
 }
 
+/*!
+  Adds custom actions to popup
+  \param menu - popup menu
+*/
 void OB_Browser::contextMenuPopup( QPopupMenu* menu )
 {
+/*  QValueList<int> cols;
+  for ( QMap<int, int>::ConstIterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
+  {
+    if ( appropriateColumn( it.key() ) )
+      cols.append( it.key() );
+  }
+
+  uint num = menu->count();
+  menu->setCheckable( true );
+  for ( QValueList<int>::const_iterator iter = cols.begin(); iter != cols.end(); ++iter )
+  {
+    QString name = columnTitle( *iter );
+    if ( name.isEmpty() )
+      continue;
+
+    int id = menu->insertItem( name, this, SLOT( onColumnVisible( int ) ) );
+    menu->setItemChecked( id, isColumnVisible( *iter ) );
+    menu->setItemParameter( id, *iter );
+  }
+  if ( menu->count() != num )
+    menu->insertSeparator();*/
+
   DataObjectList selected;
   getSelected( selected );
 
@@ -857,9 +1534,11 @@ void OB_Browser::contextMenuPopup( QPopupMenu* menu )
     menu->insertItem( tr( "MEN_EXPAND_ALL" ), this, SLOT( onExpand() ) );
     menu->insertSeparator();
   }
-  menu->insertItem( tr( "MEN_REFRESH" ), this, SLOT( onRefresh() ) );
 }
 
+/*!
+  Expands item with all it's children
+*/
 void OB_Browser::expand( QListViewItem* item )
 {
   if ( !item )
@@ -870,6 +1549,9 @@ void OB_Browser::expand( QListViewItem* item )
     expand( child );
 }
 
+/*!
+  \return true if item or one of it's children isn't opened
+*/
 bool OB_Browser::hasClosed( QListViewItem* item ) const
 {
   if ( !item )
@@ -884,3 +1566,107 @@ bool OB_Browser::hasClosed( QListViewItem* item ) const
 
   return has;
 }
+
+/*!
+  Removes SUIT object
+  \param obj - SUIT object to be removed
+  \param autoUpd - auto tree updating
+*/
+void OB_Browser::removeObject( SUIT_DataObject* obj, const bool autoUpd )
+{
+  if ( !obj )
+    return;
+
+  // Removing list view items from <myItems> recursively for all children.
+  // Otherwise, "delete item" line will destroy all item's children,
+  // and <myItems> will contain invalid pointers (see ~QListViewItem() description in Qt docs)
+  DataObjectList childList;
+  obj->children( childList, true );
+  for ( DataObjectListIterator it( childList ); it.current(); ++it )
+  {
+    it.current()->disconnect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
+    myItems.remove( it.current() );
+  }
+
+  QListViewItem* item = listViewItem( obj );
+
+  obj->disconnect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
+  myItems.remove( obj );
+
+  if ( obj == myRoot )
+  {
+    // remove all child list view items
+    setRootObject( 0 );
+    return;
+  }
+
+  if( !autoUpd )
+    return;
+
+  if ( isAutoUpdate() )
+  {
+    SUIT_DataObject* pObj = item && item->parent() ? dataObject( item->parent() ) : 0;
+    updateTree( pObj, false );
+  }
+
+  delete item;
+}
+
+/*!
+  Opens branches from 1 to autoOpenLevel()
+  \sa autoOpenLevel()
+*/
+void OB_Browser::autoOpenBranches()
+{
+  openLevels();
+}
+
+/*!
+  Opens branch
+  \param item
+  \param level
+*/
+void OB_Browser::openBranch( QListViewItem* item, const int level )
+{
+  if ( level < 1 )
+    return;
+
+  while ( item )
+  {
+    item->setOpen( true );
+    openBranch( item->firstChild(), level - 1 );
+    item = item->nextSibling();
+  }
+}
+
+/*!
+  SLOT: called on double click on item, emits signal
+*/
+void OB_Browser::onDoubleClicked( QListViewItem* item )
+{
+  if ( item )
+    emit doubleClicked( dataObject( item ) );
+}
+
+/*!
+  Stores time of last modification
+*/
+void OB_Browser::setModified()
+{
+  myModifiedTime = clock();
+}
+
+OB_ObjSearch* OB_Browser::getSearch() const
+{
+  return myFindDlg->getSearch();
+}
+
+void OB_Browser::setSearch( OB_ObjSearch* s )
+{
+  myFindDlg->setSearch( s );
+}
+
+void OB_Browser::enableSearch( const bool on )
+{
+  myFindDlg->setShown( on );
+}