Salome HOME
Copyright update 2022
[modules/gui.git] / src / ObjBrowser / OB_Browser.cxx
old mode 100755 (executable)
new mode 100644 (file)
index dd6012a..acf7ecc
@@ -1,46 +1,57 @@
-// Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
-// 
+// Copyright (C) 2007-2022  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
 // 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 
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// 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 
+// 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/
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
+
+// File   : OB_Browser.cxx
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+
 #include "OB_Browser.h"
 
-#include "OB_Filter.h"
-#include "OB_ListItem.h"
-#include "OB_ListView.h"
+//#include "OB_Filter.h"
+//#include "OB_ListItem.h"
+//#include "OB_ListView.h"
 
-#include <SUIT_DataObjectIterator.h>
-#include <SUIT_TreeSync.h>
+#include <QtxTreeView.h>
+#include <QtxSearchTool.h>
+//#include <SUIT_DataObjectIterator.h>
 
-#include <qcursor.h>
-#include <qlayout.h>
-#include <qtooltip.h>
-#include <qpainter.h>
-#include <qwmatrix.h>
-#include <qlistview.h>
-#include <qpopupmenu.h>
-#include <qdatetime.h>
+#include <QAction>
+#include <QMenu>
+#include <QItemSelection>
+#include <QKeyEvent>
+#include <QVBoxLayout>
+#include <QAbstractItemModel>
+#include <QAbstractItemDelegate>
+#include <QHeaderView>
 
 #include <time.h>
 
+
 /*!
-    Class: OB_Browser::ToolTip
-    Descr: Tool tip for OB_Browser.
+  \class  OB_Browser::ToolTip
+  Tool tip for OB_Browser.
 */
 
+//TODO: ToolTip commented - to be removed or revised
+/*
 class OB_Browser::ToolTip : public QToolTip
 {
 public:
@@ -52,21 +63,36 @@ public:
 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;
+          return;
 
   QListView* lv = myBrowser->listView();
 
@@ -84,404 +110,417 @@ void OB_Browser::ToolTip::maybeTip( const QPoint& pos )
 
   tip( aRect, aText );
 }
+*/
 
 
-typedef SUIT_DataObject*   ObjPtr;
-typedef OB_ListItem*       ItemPtr;
 /*!
-    Class: OB_BrowserSync
-    Descr: Auxiliary class for synchronizing tree of SUIT_DataObjects and list view items
+  \class OB_Browser
+  \brief Object browser widget which can be used to handle tree-like data model.
+
+  The class OB_Browser implements public API of an object browser widget
+  that can be used to display arbitrary application data in a hierarchical form.
+  It is based on Qt4 model/view architecture. 
+
+  Object browser can be used with conjuction of any custom item model inherited
+  from QAbstractItemModel class (see Qt 4 reference manual).
+
+  The class provides a functionality get/modify selection, drag-n-drop of the
+  objects, etc.
 */
 
-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 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;
-};
+/*!
+  \brief Constructor
+  \param parent paren widget
+  \param model data model
+*/
+OB_Browser::OB_Browser( QWidget* parent, QAbstractItemModel* model )
+: QWidget( parent ),
+  myAutoOpenLevel( 0 )
+{
+  // set-up tree view
+  myView = new QtxTreeView( this );                                  // create tree view
+  myView->setRootIsDecorated( true );                                // show root item
+  myView->setSelectionMode( QAbstractItemView::ExtendedSelection );  // enable extended selection mode
+  myView->setAllColumnsShowFocus( true );                            // focus is shown in all columns
+
+  // enable drag-n-drop support
+  myView->setDragDropMode( QAbstractItemView::DragDrop );            // enable both drag and drop operations
+  myView->setDropIndicatorShown( true );                             // show drag indicator on dragging
+
+  // set-up search tool
+  mySearchTool = new QtxSearchTool( this, myView );                  // create search tool
+  mySearchTool->setFrameStyle( QFrame::NoFrame | QFrame::Plain );    // do not show frame
+  mySearchTool->setActivators( QtxSearchTool::StandardKey | QtxSearchTool::SlashKey ); // set activation mode
+  mySearchTool->setSearcher( new QtxTreeViewSearcher( myView ) );    // assign searcher (for tree view)
+  
+  // layout widgets
+  QVBoxLayout* main = new QVBoxLayout( this );
+  main->addWidget( myView );
+  main->addWidget( mySearchTool );
+  main->setMargin( 0 );
+  main->setSpacing( 3 );
 
+  // TODO: decide what to do with tooltip
+  //myShowToolTips = true;
+  //myTooltip = new ToolTip( this, myView->viewport() );
 
-OB_BrowserSync::OB_BrowserSync( OB_Browser* ob )
-: myBrowser( ob )
-{
-}
-
-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() );
-      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;
-}
+  // TODO: drag-n-drop works differently - SUIT_TreeModel to be updated
+  // and QTreeView needs some setup
+  //connect( myView, SIGNAL( dropped( QPtrList<QListViewItem>, QListViewItem*, int ) ),
+  //         this, SLOT( onDropped( QPtrList<QListViewItem>, QListViewItem*, int ) ) );
+  setModel( model );
 
-void OB_BrowserSync::updateItem( const ItemPtr& p ) const
-{
-  if ( p && needUpdate( p ) ) { 
-    //    printf( "--- needUpdate for %s = true ---\n", p->text( 0 ).latin1() );
-    p->update();
-  }
+  connect( myView, SIGNAL( selectionChanged() ),
+           this,   SIGNAL( selectionChanged() ) );
 }
 
-ItemPtr OB_BrowserSync::createItem( const ObjPtr& src,
-                                   const ItemPtr& parent, const ItemPtr& after,
-                                   const bool prepend ) const
+/*!
+  \brief Destructor.
+*/
+OB_Browser::~OB_Browser()
 {
-  ItemPtr i = myBrowser ? dynamic_cast<ItemPtr>( myBrowser->createItem( src, parent, after, prepend ) ) : 0;
-  if( i )
-    i->setOpen( src->isOpen() );
-  return i;
+  //delete myTooltip;
+  //setUpdater( 0 );
 }
 
-void OB_BrowserSync::deleteItemWithChildren( const ItemPtr& i ) const
+/*!
+  \brief Get data model.
+  \return data model
+  \sa setModel()
+*/
+QAbstractItemModel* OB_Browser::model() const
 {
-  if( myBrowser && myBrowser->myItems.contains( i->dataObject() ) )
-  {
-    myBrowser->removeReferences( i );
-    delete i;
-  }
+  return myView->model();
 }
 
-bool OB_BrowserSync::isEqual( const ObjPtr& p, const ItemPtr& q ) const
+/*!
+  \brief Set data model.
+  \param model data model
+  \sa model()
+*/
+void OB_Browser::setModel( QAbstractItemModel* model )
 {
-  return ( !p && !q ) || ( p && q && q->dataObject()==p );
+  myView->setModel( model );
+  myView->update();
+  setModified();
 }
 
-ObjPtr OB_BrowserSync::nullSrc() const
+/*!
+  \brief Get current item delegate (items renderer).
+  \return currently used item delegate
+  \sa setItemDelegate()
+*/
+QAbstractItemDelegate* OB_Browser::itemDelegate() const
 {
-  return 0;
+  return myView->itemDelegate();
 }
 
-ItemPtr OB_BrowserSync::nullTrg() const
+/*!
+  \brief Set item delegate (items renderer).
+  \param d custom item delegate
+  \sa itemDelegate()
+*/
+void OB_Browser::setItemDelegate( QAbstractItemDelegate* d )
 {
-  return 0;
+  myView->setItemDelegate( d );
 }
 
-void OB_BrowserSync::children( const ObjPtr& p, QValueList<ObjPtr>& ch ) const
+/*!
+  \brief Check if controls for expanding and collapsing top-level items are shown.
+  \return \c true if top-level items are decorated
+  \sa setRootIsDecorated()
+*/
+bool OB_Browser::rootIsDecorated() const
 {
-  DataObjectList l;
-  if( p )
-  {
-    p->children( l );
-    ch.clear();
-    for( SUIT_DataObject* o = l.first(); o; o = l.next() )
-      ch.append( o );
-  }
+  return myView->rootIsDecorated();
 }
 
-void OB_BrowserSync::children( const ItemPtr& p, QValueList<ItemPtr>& ch ) const
+/*!
+  \brief Show/hide controls for expanding and collapsing top-level items.
+  \param decor if \c true, top-level items are decorated
+  \sa rootIsDecorated()
+*/
+void OB_Browser::setRootIsDecorated( const bool decor )
 {
-  for( QListViewItem* item = p->firstChild(); item; item = item->nextSibling() )
-  {
-    ItemPtr p = dynamic_cast<ItemPtr>( item );
-    if( p )
-      ch.append( p );
-  }
+  if ( decor != rootIsDecorated() )
+    myView->setRootIsDecorated( decor );
 }
 
-ItemPtr OB_BrowserSync::parent( const ItemPtr& p ) const
+/*
+  \brief Check if "Sorting" popup menu command for the header is enabled.
+  \return \c true if "Sorting" menu command is enabled
+  \sa setSortMenuEnabled()
+*/
+bool OB_Browser::sortMenuEnabled() const
 {
-  return p ? dynamic_cast<ItemPtr>( p->parent() ) : 0;
+  return myView->sortMenuEnabled();
 }
 
-
-/*!
-    Class: OB_Browser
-    Descr: Hierarchical tree object browser.
+/*
+  \brief Enable/disable "Sorting" popup menu command for the header.
+  \param enableSortMenu if \c true, enable "Sorting" menu command
+  \sa sortMenuEnabled()
 */
-
-OB_Browser::OB_Browser( QWidget* parent, SUIT_DataObject* root )
-: QFrame( parent ),
-
-myRoot( 0 ),
-myTooltip( 0 ),
-myAutoOpenLevel( 0 ),
-myAutoUpdate( false ),
-myAutoDelObjs( false ),
-myRootDecorated( true )
+void OB_Browser::setSortMenuEnabled( const bool enabled )
 {
-  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 );
-
-  QVBoxLayout* main = new QVBoxLayout( this );
-  main->addWidget( myView );
-
-  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();
+  if ( enabled != sortMenuEnabled() )
+    myView->setSortMenuEnabled( enabled );
 }
 
-OB_Browser::~OB_Browser()
+/*!
+  \brief Get search tool widget.
+  \return search tool widget
+  \sa isSearchToolEnabled(), setSearchToolEnabled()
+*/
+QtxSearchTool* OB_Browser::searchTool() const
 {
-  myItems.clear();
-  delete myTooltip;
+  return mySearchTool;
 }
 
-bool OB_Browser::rootIsDecorated() const
+/*!
+  \brief Check if search tool is enabled.
+  \return \c true if search tool is enabled
+  \sa setSearchToolEnabled(), searchTool()
+*/
+bool OB_Browser::isSearchToolEnabled() const
 {
-  return myRootDecorated;
+  return mySearchTool->isEnabled();
 }
 
-void OB_Browser::setRootIsDecorated( const bool decor )
+/*!
+  \brief Enable/disable search tool.
+  \param enable pass \c true to enable search tool
+  \sa isSearchToolEnabled(), searchTool()
+*/
+void OB_Browser::setSearchToolEnabled( const bool enable )
 {
-  if ( decor == rootIsDecorated() ) 
+  if ( mySearchTool->isEnabled() == enable )
     return;
 
-  myRootDecorated = decor;
-  updateTree( 0, false );
+  mySearchTool->setEnabled( enable );
+  if ( !mySearchTool->isEnabled() )
+    mySearchTool->hide();
 }
 
+/*!
+  \brief Get number of levels which should be automatically expanded
+  when updating the data tree.
+  \return number of levels to be auto-opened on tree updating
+  \sa setAutoOpenLevel()
+*/
 int OB_Browser::autoOpenLevel() const
 {
   return myAutoOpenLevel;
 }
 
-void OB_Browser::setAutoOpenLevel( const int level )
+/*!
+  \brief Set number of levels which should be automatically expanded
+  when updating the data tree.
+  \param levels number of levels to be auto-opened on tree updating
+  \sa autoOpenLevel()
+*/
+void OB_Browser::setAutoOpenLevel( const int levels )
 {
-  if ( myAutoOpenLevel == level )
-    return;
+  if ( myAutoOpenLevel != levels )
+    myAutoOpenLevel = levels;
+}
 
-  myAutoOpenLevel = level;
+/*!
+  \brief Expand all branches to the specified number of levels.
 
-  autoOpenBranches();
+  If \a levels value is negative, then autoOpenLevel() value is used instead.
+  
+  \param levels number of levels to be expanded
+  \sa autoOpenLevel()
+*/
+void OB_Browser::openLevels( const int levels )
+{
+  myView->expandLevels( levels < 0 ? autoOpenLevel() : levels );
 }
 
+/*!
+  \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;
 }
+*/
 
-bool OB_Browser::isAutoUpdate() const
+/*!
+  \brief Get number of selected items.
+  \return number of selected items
+*/
+int OB_Browser::numberOfSelected() const
 {
-  return myAutoUpdate;
+  // we take selection by rows
+  return myView->selectionModel() ? myView->selectionModel()->selectedRows().count() : 0;
 }
 
-void OB_Browser::setAutoUpdate( const bool on )
+/*!
+  \brief Get all selected items.
+  \return unsorted list of selected indexes with no duplicates
+*/
+QModelIndexList OB_Browser::selectedIndexes() const
 {
-  myAutoUpdate = on;
+  // we take selection by rows
+  return myView->selectionModel() ? myView->selectionModel()->selectedRows() : QModelIndexList();
 }
 
-bool OB_Browser::isAutoDeleteObjects() const
+/*!
+  \brief Get selection containing information about selected ranges.
+  \return QItemSelection instance
+*/
+const QItemSelection OB_Browser::selection() const
 {
-  return myAutoDelObjs;
+  static QItemSelection emptySel;
+  QItemSelection sel = emptySel;
+  if ( myView->selectionModel() )
+    sel = myView->selectionModel()->selection();
+  return sel;
 }
 
-void OB_Browser::setAutoDeleteObjects( const bool on )
+/*!
+  \brief Select/deselect specified model index.
+  \param index model index to be selected/deselected
+  \param on if \c true, the index will be selected, otherwise - deselected
+  \param keepSelection if \c true (default) the previous selection is kept, 
+  otherwise it is first cleared
+*/
+void OB_Browser::select( const QModelIndex& index, const bool on, const bool keepSelection )
 {
-  myAutoDelObjs = on;
-}
+  if ( myView->selectionModel() ) {
+    QItemSelectionModel::SelectionFlags f = on ? QItemSelectionModel::Select : QItemSelectionModel::Deselect;
+    f = f | QItemSelectionModel::Rows;
+    if ( !keepSelection )
+      f = f | QItemSelectionModel::Clear;
 
-SUIT_DataObject* OB_Browser::getRootObject() const
-{
-  return myRoot;
+    myView->selectionModel()->select( index, f );
+  }
 }
 
-void OB_Browser::setRootObject( SUIT_DataObject* theRoot )
+/*!
+  \brief Select/deselect specified model indices.
+  \param indexes model indices to be selected/deselected
+  \param on if \c true, the indices will be selected, otherwise - deselected
+  \param keepSelection if \c true (default) the previous selection is kept, 
+  otherwise it is first cleared
+*/
+void OB_Browser::select( const QModelIndexList& indexes, const bool on, const bool keepSelection )
 {
-  DataObjectKey curKey;
-  DataObjectMap selObjs, openObjs;
-  DataObjectKeyMap selKeys, openKeys;
-
-  int selNum = numberOfSelected();
+  bool blocked = myView->signalsBlocked();
+  myView->blockSignals( true );
 
-  SUIT_DataObject* curObj = 0;
-  if ( theRoot )
-    curObj = storeState( selObjs, openObjs, selKeys, openKeys, curKey );
+  QModelIndex idx;
 
-  removeConnections( myRoot );
-  if ( myRoot != theRoot && isAutoDeleteObjects() )
-    delete myRoot;
-
-  myRoot = theRoot;
-
-  createConnections( myRoot );
-
-  if ( myRoot )
-    updateView( myRoot );
-  else if ( listView() )
-  {
-    myItems.clear();
-    listView()->clear();
+  if ( !indexes.isEmpty() ) {
+    QItemSelection mysel;
+    // select by range if indexes are contiguous
+    QModelIndex first=indexes.at(0);
+    QModelIndex last=first;
+    if (indexes.size() > 1) {
+      for (int i = 1; i < indexes.size(); ++i) 
+      {
+        idx=indexes.at(i);
+        if(idx.parent().row()==last.parent().row() && idx.parent().column()==last.parent().column() &&
+           idx.row()==last.row()+1 && idx.column()==last.column())
+        {
+          // index is contiguous to last: extend the range
+          last=idx;
+        }
+        else
+        {
+          // index idx is not contiguous: create a new range
+          mysel.select(first,last);
+          first=idx;
+          last=idx;
+        }
+      }
+    }
+    mysel.select(first,last);
+
+    if ( myView->selectionModel() ) {
+      QItemSelectionModel::SelectionFlags f = on ? QItemSelectionModel::Select : QItemSelectionModel::Deselect;
+      f = f | QItemSelectionModel::Rows;
+      if ( !keepSelection )
+        f = f | QItemSelectionModel::Clear;
+      myView->selectionModel()->select( mysel, f );
+    }
   }
-
-  restoreState( selObjs, openObjs, curObj, selKeys, openKeys, curKey );
-
-  autoOpenBranches();
-
-  setModified();
-
-  if ( selNum != numberOfSelected() )
-    emit selectionChanged();
-}
-
-int OB_Browser::numberOfSelected() const
-{
-  int count = 0;
-  if ( listView() )
+  else if ( !keepSelection )
   {
-    for ( QListViewItemIterator it( listView() ); it.current(); ++it )
-      if ( it.current()->isSelected() ) 
-        count++;
+    myView->clearSelection();
   }
-  return count;
-}
 
-DataObjectList OB_Browser::getSelected() const
-{
-  DataObjectList lst;
-  getSelected( lst );
-  return lst;
+  myView->blockSignals( blocked );
+  emit( selectionChanged() );
 }
 
-void OB_Browser::getSelected( DataObjectList& theObjList ) const
+/*!
+  \brief Check if specified model index is expanded or collapsed.
+  \param index model index
+  \return \c true if model index is expanded
+  \sa setOpen()
+*/
+bool OB_Browser::isOpen( const QModelIndex& index ) const
 {
-  theObjList.clear();
-
-  if ( !listView() )
-    return;
-
-  for ( QListViewItemIterator it( listView() ); it.current(); ++it )
-  {
-    if ( it.current()->isSelected() ) 
-    {
-      SUIT_DataObject* obj = dataObject( it.current() );
-      if ( obj )
-       theObjList.append( obj );
-    }
-  }
+  return index.isValid() && model() && model()->hasChildren( index ) && myView->isExpanded( index );
 }
 
-void OB_Browser::setSelected( const SUIT_DataObject* theObject, const bool append )
+/*!
+  \brief Expand/collapse the specified model index.
+  \param index model index
+  \param open if \c true, the index will be expanded, otherwse - collapsed
+  \sa isOpen()
+*/
+void OB_Browser::setOpen( const QModelIndex& index, const bool open )
 {
-  DataObjectList lst;
-  lst.append( theObject );
-  setSelected( lst, append );
+  myView->setExpanded( index, open );  // hasChildren() ???
 }
 
-void OB_Browser::setSelected( const DataObjectList& theObjLst, const bool append )
+/*!
+  \brief Adjust first column width to its contents.
+*/
+void OB_Browser::adjustWidth()
 {
-  QListView* lv = listView();
-
-  if ( !lv )
-    return;
-
-  bool changed = false;
-  bool block = lv->signalsBlocked();
-  lv->blockSignals( true );
-
-  QMap<QListViewItem*, int> map;
-  for ( DataObjectListIterator itr( theObjLst ); itr.current(); ++itr )
-    map.insert( listViewItem( itr.current() ), 0 );
-
-  for ( QListViewItemIterator it( lv ); it.current(); ++it )
-  {
-    QListViewItem* item = it.current();
-    if ( map.contains( item ) && !lv->isSelected( item ) )
-    {
-      changed = true;
-      lv->setSelected( item, true );
-    }
-    if ( !append && !map.contains( item ) && lv->isSelected( item ) )
-    {
-      changed = true;
-      lv->setSelected( item, false );
-    }
-  }
-
-  lv->blockSignals( block );
-
-  if ( changed )
-  {
-    int count = 0;
-    QListViewItem* sel = 0;
-    QListViewItem* cur = lv->currentItem();
-    for ( QListViewItemIterator iter( lv ); iter.current() && !sel; ++iter, count++ )
-    {
-      if ( iter.current()->isSelected() && cur == iter.current() )
-        sel = iter.current();
-    }
-
-    for ( QListViewItemIterator itr( lv ); itr.current() && !sel; ++itr )
-    {
-      if ( itr.current()->isSelected() )
-             sel = itr.current();
-    }
-
-    if ( sel )
-      lv->setCurrentItem( sel );
-
-    if ( sel && count == 1 )
-      lv->ensureItemVisible( sel );
-
-    emit selectionChanged();
-  }
+  myView->resizeColumnToEncloseContents( 0 );
 }
 
-bool OB_Browser::isOpen( SUIT_DataObject* theObject ) const
+/*!
+  \brief Adjust first column width to its contents.
+*/
+void OB_Browser::adjustFirstColumnWidth()
 {
-  bool res = false;
-  if ( listView() )
-    res = listView()->isOpen( listViewItem( theObject ) );
-  return res;
+  myView->resizeColumnToEncloseContents( 0 );
 }
 
-void OB_Browser::setOpen( SUIT_DataObject* theObject, const bool theOpen )
+/*!
+  \brief Adjust all columns width to its contents except the first column.
+*/
+void OB_Browser::adjustColumnsWidth()
 {
-  if ( listView() )
-    listView()->setOpen( listViewItem( theObject ), theOpen );
+  for ( int aCol = 1; aCol < myView->header()->count(); aCol++ ) {
+    if ( myView->columnWidth( aCol ) > 0 )
+      myView->resizeColumnToEncloseContents( aCol );
+  }
 }
 
+/*!
+  \return SUIT object correspondint to item at position 'pos'
+  \param pos - position
+*/
+/* TODO: removed - QTreeView::indexAt() should be used
 SUIT_DataObject* OB_Browser::dataObjectAt( const QPoint& pos ) const
 {
   SUIT_DataObject* obj = 0;
@@ -492,162 +531,45 @@ SUIT_DataObject* OB_Browser::dataObjectAt( const QPoint& pos ) const
 
   return obj;
 }
-
+*/
+/*!
+  \return filter of list view
+*/
+/* TODO: removed
 OB_Filter* OB_Browser::filter() const
 {
   return myView->filter();
 }
-
+*/
+/*!
+  Changes filter of list view
+  \param f - new filter
+*/
+/* TODO: removed
 void OB_Browser::setFilter( OB_Filter* f )
 {
   myView->setFilter( f );
 }
-
-int OB_Browser::addColumn( const QString& label, const int id, const int width )
-{
-  return addColumn( QIconSet(), label, id, width );
-}
-
-int OB_Browser::addColumn( const QIconSet& icon, const QString& label, const int id, const int width )
-{
-  QListView* lv = listView();
-  if ( !lv )
-    return -1;
-
-  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 theId;
-}
-
-void OB_Browser::removeColumn( const int id )
-{
-  QListView* lv = listView();
-  if ( !lv || !myColumnIds.contains( id ) )
-    return;
-
-  int sec = myColumnIds[id];
-  lv->removeColumn( sec );
-
-  // update map of column indeces
-  myColumnIds.remove( id );
-  for ( QMap<int, int>::iterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
-  {
-    if ( it.key() > id )
-      it.data()--;
-  }
-  updateText();
-}
-
-void OB_Browser::setNameTitle( const QString& label )
-{
-  setNameTitle( QIconSet(), label );
-}
-
-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 );
-}
-
-void OB_Browser::setColumnTitle( const int id, const QString& label )
-{
-  setColumnTitle( id, QIconSet(), label );
-}
-
-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 );
-}
-
-QString OB_Browser::nameTitle() const
-{
-  return myView->columnText( 0 );
-}
-
-QString OB_Browser::columnTitle( const int id ) const
-{
-  QString txt;
-  if ( myColumnIds.contains( id ) )
-    txt = myView->columnText( myColumnIds[id] );
-  return txt;
-}
-
-bool OB_Browser::isColumnVisible( const int id ) const
-{
-  return myColumnIds.contains( id ) && myView->isShown( myColumnIds[id] );
-}
-
-void OB_Browser::setColumnShown( const int id, const bool on )
-{
-  if ( !myColumnIds.contains( id ) )
-    return;
-
-  myView->setShown( myColumnIds[id], on );
-}
-
-void OB_Browser::setWidthMode( QListView::WidthMode mode )
-{
-  for ( int i = 0, n = myView->columns(); i < n; i++ )
-    myView->setColumnWidthMode( i, mode );
-}
-
-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;
-}
-
-bool OB_Browser::appropriateColumn( const int id ) const
-{
-  bool res = false;
-  if ( myColumnIds.contains( id ) )
-    res = myView->appropriate( myColumnIds[id] );
-  return res;
-}
-
-void OB_Browser::setAppropriateColumn( const int id, const bool on )
+*/
+/*!
+  Sets global width mode
+  \param mode - new width mode
+*/
+/* TODO: removed
+void OB_Browser::setWidthMode( QListView::WidthMode mode )
 {
-  if ( !myColumnIds.contains( id ) )
-    return;
-
-  myView->setAppropriate( myColumnIds[id], on );
+  for ( int i = 0, n = myView->columns(); i < n; i++ )
+    if( mode!=QListView::Maximum || myView->columnWidth( i )>0 )
+      myView->setColumnWidthMode( i, mode );
 }
-
+*/
+/*!
+  Updates tree
+  \param obj - start object
+  \param autoOpen - to open automatically branches of autoOpenLevel()
+  \sa autoOpenLevel()
+*/
+/* TODO: removed
 void OB_Browser::updateTree( SUIT_DataObject* obj, const bool autoOpen )
 {
 //  QTime t1 = QTime::currentTime();
@@ -667,7 +589,7 @@ void OB_Browser::updateTree( SUIT_DataObject* obj, const bool autoOpen )
 
   restoreState( selObjs, openObjs, curObj, selKeys, openKeys, curKey );
 
-  if( autoOpen )
+  if ( autoOpen )
     autoOpenBranches();
 
   setModified();
@@ -678,7 +600,11 @@ void OB_Browser::updateTree( SUIT_DataObject* obj, const bool autoOpen )
 //  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'
+*/
+/* TODO: removed
 void OB_Browser::replaceTree( SUIT_DataObject* src, SUIT_DataObject* trg )
 {
   if ( !src || !trg || src == trg || src->root() != getRootObject() )
@@ -711,160 +637,17 @@ void OB_Browser::replaceTree( SUIT_DataObject* src, SUIT_DataObject* trg )
 
   restoreState( selObjs, openObjs, curObj, selKeys, openKeys, curKey );
 
-  autoOpenBranches();
-
   setModified();
 
   if ( selNum != numberOfSelected() )
     emit selectionChanged();
 }
-
-void OB_Browser::updateView( SUIT_DataObject* startObj )
-{
-  QListView* lv = listView();
-  if ( !lv )
-    return;
-
-  if ( !startObj || startObj->root() != getRootObject() )
-    return;
-
-  if ( startObj == myRoot )
-  {
-    DataObjectList ch;
-    myRoot->children( ch );
-
-    ItemMap exist;
-    QListViewItem* st = lv->firstChild();
-    for( ; st; st =  st->nextSibling() )
-    {
-      OB_ListItem* ob_item = dynamic_cast<OB_ListItem*>( st );
-      exist.insert( ob_item->dataObject(), ob_item );
-    }
-
-    SUIT_DataObject* local_root = ch.first();
-    for( ; local_root; local_root = ch.next() )
-    {
-      OB_BrowserSync sync( this );
-      OB_ListItem* local_item = dynamic_cast<OB_ListItem*>( listViewItem( local_root ) );
-      synchronize<ObjPtr,ItemPtr,OB_BrowserSync>( local_root, local_item, sync );
-      exist[local_root] = 0;
-    }
-
-    ItemMap::const_iterator anIt = exist.begin(), aLast = exist.end();
-    for( ; anIt!=aLast; anIt++ )
-    {
-      if( anIt.data() ) // exist[local_root]==1 -> this local root was NOT in data model, should be removed
-      {
-       removeReferences( anIt.data() );
-       OB_ListItem* item = dynamic_cast<OB_ListItem*>( anIt.data() );
-       if( item && myItems.contains( item->dataObject() ) )
-         delete anIt.data();
-      }
-    }
-  }
-  else
-  {
-    OB_BrowserSync sync( this );
-    OB_ListItem* startItem = dynamic_cast<OB_ListItem*>( listViewItem( startObj ) );
-    synchronize<ObjPtr,ItemPtr,OB_BrowserSync>( startObj, startItem, sync );
-  }
-}
-
-QListViewItem* OB_Browser::createItem( const SUIT_DataObject* o, QListViewItem* parent,
-                                      QListViewItem* after, const bool prepend )
-{
-  QListView* lv = listView();
-
-  if ( !lv || !o )
-    return 0;
-
-  QListViewItem* item = 0;
-  SUIT_DataObject* obj = (SUIT_DataObject*)o;
-
-  int type = -1;
-
-  switch ( obj->checkType() )
-  {
-  case SUIT_DataObject::CheckBox:
-    type = QCheckListItem::CheckBox;
-    break;
-  case SUIT_DataObject::RadioButton:
-    type = QCheckListItem::RadioButton;
-    break;
-  }
-
-  if ( parent )
-  {
-    if ( after ) 
-    {
-      if ( type == -1 )
-       item = new OB_ListItem( obj, parent, after );
-      else
-       item = new OB_CheckListItem( obj, parent, after, (QCheckListItem::Type)type );
-    }
-    else if ( prepend )
-    {
-      if ( type == -1 )
-       item = new OB_ListItem( obj, parent );
-      else
-       item = new OB_CheckListItem( obj, parent,  (QCheckListItem::Type)type );
-    }
-    else // append
-    {
-      after = parent->firstChild();
-      while ( after && 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 );
-    }
-  }
-  else
-  {
-    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;
-}
-
-void OB_Browser::adjustWidth()
-{
-  if ( !listView() )
-    return;
-
-  listView()->setColumnWidth( 0, 0 );
-  if ( listView()->firstChild() )
-    adjustWidth( listView()->firstChild() );
-}
-
+*/
+/*!
+  Adjusts width by item
+  \param item
+*/
+/*
 void OB_Browser::adjustWidth( QListViewItem* item )
 {
   while ( item )
@@ -875,34 +658,12 @@ void OB_Browser::adjustWidth( QListViewItem* item )
     item = item->nextSibling();
   }
 }
+*/
 
-SUIT_DataObject* OB_Browser::dataObject( const QListViewItem* item ) const
-{
-  SUIT_DataObject* obj = 0;
-
-  if ( item && item->rtti() == OB_ListItem::RTTI() )
-    obj = ((OB_ListItem*)item)->dataObject();
-  else if ( item && item->rtti() == OB_CheckListItem::RTTI() )
-    obj = ((OB_CheckListItem*)item)->dataObject();
-
-  return obj;
-}
-
-QListViewItem* OB_Browser::listViewItem( const SUIT_DataObject* obj ) const
-{
-  QListViewItem* item = 0;
-
-  if ( myItems.contains( (SUIT_DataObject*)obj ) )
-    item = myItems[(SUIT_DataObject*)obj];
-
-  return item;
-}
-
-QListView* OB_Browser::listView() const
-{
-  return myView;
-}
-
+/*!
+  \remove all items referencing current (through data objects)
+*/
+/* TODO:
 void OB_Browser::removeReferences( QListViewItem* item )
 {
   if ( !item )
@@ -919,7 +680,11 @@ void OB_Browser::removeReferences( QListViewItem* item )
     i = i->nextSibling();
   }
 }
-
+*/
+/*!
+  Connects all children to SLOT onDestroyed
+*/
+/* TODO: move to SUIT_TreeModel
 void OB_Browser::createConnections( SUIT_DataObject* obj )
 {
   if ( !obj )
@@ -933,7 +698,11 @@ void OB_Browser::createConnections( SUIT_DataObject* obj )
   for ( DataObjectListIterator it( childList ); it.current(); ++it )
     it.current()->connect( this, SLOT( onDestroyed( SUIT_DataObject* ) ) );
 }
-
+*/
+/*!
+  Disconnects all children from SLOT onDestroyed
+*/
+/* TODO: move to SUIT_TreeModel
 void OB_Browser::removeConnections( SUIT_DataObject* obj )
 {
   if ( !obj )
@@ -947,7 +716,15 @@ void OB_Browser::removeConnections( SUIT_DataObject* 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
+*/
+/* TODO: to be revised
 SUIT_DataObject* OB_Browser::storeState( DataObjectMap& selObjs, DataObjectMap& openObjs,
                                          DataObjectKeyMap& selKeys, DataObjectKeyMap& openKeys,
                                          DataObjectKey& curKey ) const
@@ -976,7 +753,14 @@ 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
+*/
+/* TODO: to be revised
 void OB_Browser::restoreState( const DataObjectMap& selObjs, const DataObjectMap& openObjs,
                                const SUIT_DataObject* curObj, const DataObjectKeyMap& selKeys,
                                const DataObjectKeyMap& openKeys, const DataObjectKey& curKey )
@@ -1011,8 +795,8 @@ void OB_Browser::restoreState( const DataObjectMap& selObjs, const DataObjectMap
     {
       bool parentOpen = true;
       if( item && item->parent() )
-       parentOpen = item->parent()->isOpen();
-       
+        parentOpen = item->parent()->isOpen();
+
       if ( openObjs[obj] && parentOpen )
         lv->setOpen( item, true );
     }
@@ -1020,10 +804,10 @@ void OB_Browser::restoreState( const DataObjectMap& selObjs, const DataObjectMap
     {
       bool parentOpen = true;
       if( item && item->parent() )
-       parentOpen = item->parent()->isOpen();
+        parentOpen = item->parent()->isOpen();
 
       if( parentOpen )
-       lv->setOpen( item, true );
+        lv->setOpen( item, true );
     }
 
     if ( !curItem && ( curObj == obj || ( !curKey.isNull() && curKey == key )) )
@@ -1035,12 +819,20 @@ void OB_Browser::restoreState( const DataObjectMap& selObjs, const DataObjectMap
 
   lv->blockSignals( block );
 }
-
+*/
+/*!
+  Creates object key by tree item
+*/
+/* TODO: move to SUIT_TreeModel
 OB_Browser::DataObjectKey OB_Browser::objectKey( QListViewItem* i ) const
 {
   return objectKey( dataObject( i ) );
 }
-
+*/
+/*!
+  Creates object key by SUIT object
+*/
+/* TODO: move to SUIT_TreeModel
 OB_Browser::DataObjectKey OB_Browser::objectKey( SUIT_DataObject* obj ) const
 {
   if ( !obj )
@@ -1048,33 +840,104 @@ OB_Browser::DataObjectKey OB_Browser::objectKey( SUIT_DataObject* obj ) const
 
   return DataObjectKey( obj->key() );
 }
+*/
+
+/*!
+  \brief Get tree view widget.
+  \return tree view widget of the object browser
+*/
+QtxTreeView* OB_Browser::treeView() const
+{
+  return myView;
+}
 
-void OB_Browser::keyPressEvent( QKeyEvent* e )
+/*!
+  \brief Process context menu request event.
+  \param e context menu event
+*/
+void OB_Browser::contextMenuEvent( QContextMenuEvent* e )
 {
-  if ( e->key() == Qt::Key_F5 )
-    updateTree( 0, false );
+  QMenu* popup = new QMenu();
+  
+  createPopupMenu( popup );
+
+  Qtx::simplifySeparators( popup );
 
-  QFrame::keyPressEvent( e );
+  if ( !popup->actions().isEmpty() )
+    popup->exec( e->globalPos() );
+  delete popup;
+}
+
+/*!
+  \brief Get the time of the latest updating.
+  \return latest updating time
+*/
+unsigned long OB_Browser::getModifiedTime() const
+{ 
+  return myModifiedTime; 
 }
 
-void OB_Browser::onExpand()
+/*!
+  \brief Update the time of the latest updating.
+*/
+void OB_Browser::setModified()
 {
-  DataObjectList selected;
-  getSelected( selected );
-  for ( DataObjectListIterator itr( selected ); itr.current(); ++itr )
-    expand( listViewItem( itr.current() ) );
+  myModifiedTime = clock();
+}
+
+/*!
+  \brief Called when "Expand all" popup menu command is activated.
+  
+  Expands all selected items recursively.
+*/
+void OB_Browser::onExpandAll()
+{
+  QModelIndexList indexes = selectedIndexes();
+  QModelIndex index;
+  disconnect( treeView(), SIGNAL( expanded( const QModelIndex& ) ), 
+           this,       SLOT( onExpanded( const QModelIndex& ) ) );
+  
+  foreach ( index, indexes ) {
+    myView->expandAll( index );
+  }
+  connect( treeView(), SIGNAL( expanded( const QModelIndex& ) ), 
+           this,       SLOT( onExpanded( const QModelIndex& ) ) );
+  emit(onExpanded( index));
 }
 
-void OB_Browser::onColumnVisible( int id )
+/*!
+  \brief Called when "Collapse all" popup menu command is activated.
+  
+  Collapse all selected items recursively.
+*/
+void OB_Browser::onCollapseAll()
 {
-  setColumnShown( id, !isColumnVisible( id ) );
+  QModelIndexList indexes = selectedIndexes();
+  QModelIndex index;
+
+  foreach ( index, indexes ) {
+    myView->collapseAll( index );
+  }
 }
 
+/*!
+  SLOT: called if SUIT object is destroyed
+*/
+/* TODO: moved to SUIT_TreeModel
 void OB_Browser::onDestroyed( SUIT_DataObject* obj )
 {
   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
+*/
+  // TODO: drag-n-drop works differently - SUIT_TreeModel to be updated
+  // and QTreeView needs some setup
+/*
 void OB_Browser::onDropped( QPtrList<QListViewItem> items, QListViewItem* item, int action )
 {
   SUIT_DataObject* obj = dataObject( item );
@@ -1092,7 +955,11 @@ void OB_Browser::onDropped( QPtrList<QListViewItem> items, QListViewItem* item,
   if ( !lst.isEmpty() )
     emit dropped( lst, obj, action );
 }
-
+*/
+/*!
+  Updates texts of items
+*/
+/* TODO: to be removed
 void OB_Browser::updateText()
 {
   if ( myColumnIds.isEmpty() )
@@ -1112,7 +979,29 @@ void OB_Browser::updateText()
       it.current()->setText( itr.data(), obj->text( itr.key() ) );
   }
 }
+*/
+/*!
+  \return true if item must be updated
+  \param item - item to be checked
+*/
+/* TODO: to be revised
+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
+*/
+/* TODO: to be revised
 void OB_Browser::updateText( QListViewItem* item )
 {
   SUIT_DataObject* obj = dataObject( item );
@@ -1122,68 +1011,46 @@ void OB_Browser::updateText( QListViewItem* item )
   for( QMap<int, int>::iterator it = myColumnIds.begin(); it != myColumnIds.end(); ++it )
     item->setText( it.data(), obj->text( it.key() ) );
 }
+*/
 
-bool OB_Browser::eventFilter( QObject* o, QEvent* e )
+/*!
+  \brief Add custom actions to the popup menu.
+  \param menu popup menu
+*/
+void OB_Browser::createPopupMenu( QMenu* menu )
 {
-  if ( o == myView && e->type() == QEvent::ContextMenu )
-  {
-    QContextMenuEvent* ce = (QContextMenuEvent*)e;
-    if ( ce->reason() != QContextMenuEvent::Mouse )
-      contextMenuRequest( ce );
-    return true;
-  }
-  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;
-    }
-  }
+  menu->addSeparator();
 
-  return QFrame::eventFilter( o, e );
-}
+  QModelIndexList indexes = selectedIndexes();
 
-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() );
+  bool closed = false, opened = false;
+  
+  for ( QModelIndexList::Iterator it = indexes.begin(); 
+        it != indexes.end() && !closed; ++it ) {
+    closed = hasCollased( *it );
   }
 
-  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 );
+  for ( QModelIndexList::Iterator it = indexes.begin(); 
+        it != indexes.end() && !opened; ++it ) {
+    opened = hasExpanded( *it );
   }
-  if ( menu->count() != num )
-    menu->insertSeparator();*/
-
-  DataObjectList selected;
-  getSelected( selected );
-
-  bool closed = false;
-  for ( DataObjectListIterator itr( selected ); itr.current() && !closed; ++itr )
-    closed = hasClosed( listViewItem( itr.current() ) );
 
   if ( closed )
-  {
-    menu->insertItem( tr( "MEN_EXPAND_ALL" ), this, SLOT( onExpand() ) );
-    menu->insertSeparator();
+    menu->addAction( tr( "MEN_EXPAND_ALL" ), this, SLOT( onExpandAll() ) );
+  if ( opened )
+    menu->addAction( tr( "MEN_COLLAPSE_ALL" ), this, SLOT( onCollapseAll() ) );
+
+  if ( isSearchToolEnabled() ) {
+    menu->addSeparator();
+    menu->addAction( tr( "MEN_FIND" ), searchTool(), SLOT( find() ), QKeySequence(Qt::CTRL + Qt::Key_F) );
+    menu->addSeparator();
   }
 }
 
+/*!
+  Expands item with all it's children
+*/
+/* TODO: to be revised
 void OB_Browser::expand( QListViewItem* item )
 {
   if ( !item )
@@ -1193,22 +1060,57 @@ void OB_Browser::expand( QListViewItem* item )
   for ( QListViewItem* child = item->firstChild(); child; child = child->nextSibling() )
     expand( child );
 }
+*/
+/*!
+  \brief Check if model index is collapsed or has collapsed children.
+  \return \c true if item or one of its children is collapsed
+*/
+bool OB_Browser::hasCollased( const QModelIndex& index ) const
+{
+  bool result = false;
+
+  if ( index.isValid() && model() ) {
+    bool hasChildren = model()->hasChildren( index );
+    result = hasChildren && !myView->isExpanded( index );
+    if ( !result && hasChildren ) {
+      int rows = model()->rowCount( index );
+      for ( int i = 0; i < rows && !result; i ++ ) {
+        QModelIndex child = model()->index( i, 0, index );
+        result = hasCollased( child );
+      }
+    }
+  }
+  return result;
+}
 
-bool OB_Browser::hasClosed( QListViewItem* item ) const
-{
-  if ( !item )
-    return false;
-
-  if ( item->childCount() && !item->isOpen() )
-    return true;
-
-  bool has = false;
-  for ( QListViewItem* child = item->firstChild(); child && !has; child = child->nextSibling() )
-    has = hasClosed( child );
-
-  return has;
+/*!
+  \brief Check if model index is expanded or has expanded children.
+  \return \c true if item or one of its children is expanded
+*/
+bool OB_Browser::hasExpanded( const QModelIndex& index ) const
+{
+  bool result = false;
+
+  if ( index.isValid() && model() ) {
+    bool hasChildren = model()->hasChildren( index );
+    result = hasChildren && myView->isExpanded( index );
+    if ( !result && hasChildren ) {
+      int rows = model()->rowCount( index );
+      for ( int i = 0; i < rows && !result; i ++ ) {
+        QModelIndex child = model()->index( i, 0, index );
+        result = hasExpanded( child );
+      }
+    }
+  }
+  return result;
 }
 
+/*!
+  Removes SUIT object
+  \param obj - SUIT object to be removed
+  \param autoUpd - auto tree updating
+*/
+/* TODO: moved to SUIT_TreeModel
 void OB_Browser::removeObject( SUIT_DataObject* obj, const bool autoUpd )
 {
   if ( !obj )
@@ -1248,22 +1150,23 @@ void OB_Browser::removeObject( SUIT_DataObject* obj, const bool autoUpd )
 
   delete item;
 }
-
+*/
+/*!
+  Opens branches from 1 to autoOpenLevel()
+  \sa autoOpenLevel()
+*/
+/* TODO: to be revised
 void OB_Browser::autoOpenBranches()
 {
-  int level = autoOpenLevel();
-  QListView* lv = listView();
-  if ( !lv || level < 1 )
-    return;
-
-  QListViewItem* item = lv->firstChild();
-  while ( item )
-  {
-    openBranch( item, level );
-    item = item->nextSibling();
-  }
+  openLevels();
 }
-
+*/
+/*!
+  Opens branch
+  \param item
+  \param level
+*/
+/* TODO: to be revised
 void OB_Browser::openBranch( QListViewItem* item, const int level )
 {
   if ( level < 1 )
@@ -1276,15 +1179,79 @@ void OB_Browser::openBranch( QListViewItem* item, const int level )
     item = item->nextSibling();
   }
 }
-
+*/
+/*!
+  SLOT: called on double click on item, emits signal
+*/
+/* TODO: to be revised
 void OB_Browser::onDoubleClicked( QListViewItem* item )
 {
   if ( item )
     emit doubleClicked( dataObject( item ) );
 }
+*/
 
-void OB_Browser::setModified()
+/*!
+  \fn void OB_Browser::selectionChanged();
+  \brief Emitted when selection is changed in the Object Browser.
+*/
+
+QByteArray OB_Browser::getOpenStates( int theColumn ) const
 {
-  myModifiedTime = clock();
+  QByteArray aData;
+  QDataStream aStream( &aData, QIODevice::WriteOnly );
+  MapOfOpenStates aMap;
+  const_cast<OB_Browser*>( this )->openStates( true, aMap, QModelIndex(), theColumn );
+  MapOfOpenStates::const_iterator anIt = aMap.begin(), aLast = aMap.end();
+  for( ; anIt!=aLast; anIt++ )
+  {
+    QString anEntry = anIt.key();
+    qint32 anOpenAttr = anIt.value() ? 1 : 0;
+    aStream << anEntry << anOpenAttr;
+  }
+  return aData;
+}
+
+void OB_Browser::setOpenStates( const QByteArray& theData, int theColumn )
+{
+  QByteArray* aData = const_cast<QByteArray*>( &theData );
+  QDataStream aStream( aData, QIODevice::ReadOnly );
+  MapOfOpenStates aMap;
+  while( !aStream.atEnd() )
+  {
+    QString anEntry;
+    qint32 anOpenAttr;
+    aStream >> anEntry >> anOpenAttr;
+    bool isOpen = anOpenAttr!=0;
+    aMap[anEntry] = isOpen;
+  }
+  openStates( false, aMap, QModelIndex(), theColumn );
 }
 
+void OB_Browser::openStates( bool isGet, MapOfOpenStates& theMap, const QModelIndex& theIndex, int theColumn )
+{
+  if( theIndex.isValid() )
+  {
+    QString anEntry = theIndex.sibling( theIndex.row(), theColumn ).data().toString();
+    bool isOpen;
+    if( isGet )
+    {
+      isOpen = treeView()->isExpanded( theIndex );
+      theMap[anEntry] = isOpen;
+    }
+    else
+    {
+      isOpen = theMap.contains( anEntry ) ? theMap[anEntry] : false;
+      treeView()->setExpanded( theIndex, isOpen );
+    }
+  }
+
+  const QAbstractItemModel* aModel = model();
+
+  int n = aModel->rowCount( theIndex );
+  for( int i=0; i<n; i++ )
+  {
+    QModelIndex aChild = aModel->index( i, 0, theIndex );
+    openStates( isGet, theMap, aChild, theColumn );
+  }
+}