]> SALOME platform Git repositories - modules/gui.git/commitdiff
Salome HOME
*** empty log message ***
authorvsr <vsr@opencascade.com>
Mon, 30 Jul 2007 13:56:45 +0000 (13:56 +0000)
committervsr <vsr@opencascade.com>
Mon, 30 Jul 2007 13:56:45 +0000 (13:56 +0000)
src/SUIT/Makefile.am
src/SUIT/SUIT.h
src/SUIT/SUIT_DataObject.cxx
src/SUIT/SUIT_DataObject.h
src/SUIT/SUIT_TreeModel.cxx [new file with mode: 0755]
src/SUIT/SUIT_TreeModel.h [new file with mode: 0755]
src/SUIT/SUIT_TreeSync.h
src/SUIT/resources/SUIT_msg_en.ts

index e8831c945a0686a1ba8f072f4213c0062a2b129d..4a5ad477b8275d3b53eab2906885e12b83607210 100755 (executable)
@@ -52,6 +52,7 @@ salomeinclude_HEADERS=                        \
        SUIT_Study.h                    \
        SUIT_Tools.h                    \
        SUIT_TreeSync.h                 \
+       SUIT_TreeModel.h                \
        SUIT_ViewManager.h              \
        SUIT_ViewModel.h                \
        SUIT_ViewWindow.h
@@ -80,6 +81,7 @@ dist_libsuit_la_SOURCES=              \
        SUIT_Session.cxx                \
        SUIT_Study.cxx                  \
        SUIT_Tools.cxx                  \
+       SUIT_TreeModel.cxx              \
        SUIT_ViewManager.cxx            \
        SUIT_ViewModel.cxx              \
        SUIT_ViewWindow.cxx
@@ -98,6 +100,7 @@ MOC_FILES=                           \
        SUIT_Selector_moc.cxx           \
        SUIT_Session_moc.cxx            \
        SUIT_Study_moc.cxx              \
+       SUIT_TreeModel_moc.cxx          \
        SUIT_ViewManager_moc.cxx        \
        SUIT_ViewModel_moc.cxx          \
        SUIT_ViewWindow_moc.cxx
index 151fba4d1796ccaa854b4719a71633845464dbad..62c205b686d70b7607e2d4ad0b4ea838a4ccc193 100755 (executable)
 //
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
+// File   : SUIT.h
+// Author : 
+// 
+
 #ifndef SUIT_H
 #define SUIT_H
 
-#if defined SUIT_EXPORTS
-#if defined WIN32
-#define SUIT_EXPORT __declspec( dllexport )
-#else
-#define SUIT_EXPORT
-#endif
-#else
 #if defined WIN32
-#define SUIT_EXPORT __declspec( dllimport )
+#  if defined SUIT_EXPORTS
+#    define SUIT_EXPORT __declspec( dllexport )
+#  else
+#    define SUIT_EXPORT __declspec( dllimport )
+#  endif
 #else
-#define SUIT_EXPORT
-#endif
+#  define SUIT_EXPORT
 #endif
 
 #if defined SOLARIS
@@ -52,4 +52,4 @@
 #define SUIT_ASSERT(x)
 #endif
 
-#endif
+#endif  // SUIT_H
index 186dbe195e7c0614973de262088d4e982ccf4ccb..2c430de0ed58956b4142d68238a6dc7744ba5850 100755 (executable)
@@ -1,44 +1,61 @@
 // 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 
+// 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 
+//
+// 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/ or email : webmaster.salome@opencascade.com
 //
+// File   : SUIT_DataObject.cxx
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+//
 
 #include "SUIT_DataObject.h"
-
 #include "SUIT_DataObjectKey.h"
 
+SUIT_DataObject::Signal* SUIT_DataObject::mySignal = 0;
+
 /*!
-    Constructor
+  \class SUIT_DataObject
+  \brief Data object representing the data instance in the tree-like hierarchy.
+
+  Data object represents uniform data tree structure recommended to use in the
+  SUIT-based applications.
 */
 
+/*!
+  \brief Constructor.
+
+  Creates the data object with the specified parent.
+  To create the top-level object, pass 0 as parameter.
+
+  \param p parent object
+*/
 SUIT_DataObject::SUIT_DataObject( SUIT_DataObject* p )
 : myParent( 0 ),
-myOpen( false ),
-myCheck( false ),
-mySignal( 0 ),
-myAutoDel( true )
+  myOpen( false ),
+  myCheck( false ),
+  myAutoDel( true )
 {
   setParent( p );
+  signal()->emitCreated( this );
 }
 
 /*!
-    Destructor
-*/
+  \brief Destructor.
 
+  Destroys all the children if "auto-delete children" flag is set.
+*/
 SUIT_DataObject::~SUIT_DataObject()
 {
   SUIT_DataObject* p = myParent;
@@ -48,11 +65,7 @@ SUIT_DataObject::~SUIT_DataObject()
   if ( p )
     p->removeChild( this );
 
-  if ( mySignal )
-  {
-    mySignal->emitSignal();
-    mySignal->setOwner( 0 );
-  }
+  signal()->emitDestroyed( this );
 
   for ( DataObjectList::iterator it = myChildren.begin(); it != myChildren.end(); ++it )
     (*it)->myParent = 0;
@@ -62,23 +75,22 @@ SUIT_DataObject::~SUIT_DataObject()
     for ( DataObjectList::iterator itr = myChildren.begin(); itr != myChildren.end(); ++itr )
       delete *itr;
   }
-
-  delete mySignal;
 }
 
 /*!
-    Returns the root object.
+  \brief Get the root object.
+  \return root object of the data tree
 */
-
 SUIT_DataObject* SUIT_DataObject::root() const
 {
   return parent() ? parent()->root() : (SUIT_DataObject*)this;
 }
 
 /*!
-    Returns the first child object.
+  \brief Get the first child object.
+  \return first child object or 0 if there are no children
+  \sa lastChild()
 */
-
 SUIT_DataObject* SUIT_DataObject::firstChild() const
 {
   SUIT_DataObject* child = 0;
@@ -88,9 +100,10 @@ SUIT_DataObject* SUIT_DataObject::firstChild() const
 }
 
 /*!
-    Returns the last child object.
+  \brief Get the last child object.
+  \return last child object or 0 if there are no children
+  \sa firstChild()
 */
-
 SUIT_DataObject* SUIT_DataObject::lastChild() const
 {
   SUIT_DataObject* child = 0;
@@ -100,54 +113,104 @@ SUIT_DataObject* SUIT_DataObject::lastChild() const
 }
 
 /*!
-    Returns the number of the child objects.
-*/
+  \brief Get the number of the columns provided by the data tree.
 
-int SUIT_DataObject::childCount() const
+  This method can be re-implemented in the subclasses.
+  Default implementation returns 1 ("Name" column) only.
+
+  \return number of the columns
+*/
+int SUIT_DataObject::columnCount() const
 {
-  return myChildren.count();
+  return 1;  // one column ("Name") is provided by default
 }
 
 /*!
-    Returns the index of the specified object in the child list or -1.
+  \brief Get column title.
+
+  This method can be re-implemented in the subclasses.
+  Default implementation returns the title for the first column ("Name") only.
+
+  \param index column index
+  \return title of the specified column
 */
+QString SUIT_DataObject::columnTitle( const int index ) const
+{
+  if ( index == NameIdx )
+    return QObject::tr( "NAME_COLUMN" );  // one column ("Name") is provided by default
+  return QString();
+}
 
-int SUIT_DataObject::childPos( const SUIT_DataObject* obj ) const
+/*!
+  \brief Get column icon.
+
+  This method can be re-implemented in the subclasses.
+  Default implementation returns null pixmap.
+
+  \param index column index
+  \return icon of the specified column
+*/
+QPixmap SUIT_DataObject::columnIcon( const int /*index*/ ) const
 {
-  int res = -1;
+  return QPixmap();
+}
 
-  int i = 0;
-  for ( DataObjectList::const_iterator it = myChildren.begin(); it != myChildren.end() && res == -1; ++it, i++ )
-  {
-    if ( *it == obj )
-      res = i;
-  }
+/*!
+  \brief Check if the column should appear in the tree view header popup menu
+  (to show/hide the column).
 
-  return res;
+  Default implementation returns \c false because 'Name' column should be
+  always visible.
+
+  \param index column index
+  \return \c true if the column can be shown/hidden
+*/
+bool SUIT_DataObject::appropriate( const int /*index*/ ) const
+{
+  return false;
 }
 
 /*!
-    Returns the child object with specified index.
+  \brief Get the number of the child objects.
+  \return number of the children
 */
+int SUIT_DataObject::childCount() const
+{
+  return myChildren.count();
+}
 
+/*!
+  \brief Get the index of the specified object in the child list.
+  \param obj child object
+  \return subobject position or -1 if it does not belong to this object
+*/
+int SUIT_DataObject::childPos( const SUIT_DataObject* obj ) const
+{
+  return myChildren.indexOf( (SUIT_DataObject*)obj );
+}
+
+/*!
+  \brief Get child object by the specified index.
+  \param idx child object index
+  \return child object or 0 if index is out of range
+*/
 SUIT_DataObject* SUIT_DataObject::childObject( const int idx ) const
 {
   SUIT_DataObject* child = 0;
 
-  if ( idx>= 0 && idx < (int)myChildren.count() )
-  {
-    SUIT_DataObject* that = (SUIT_DataObject*)this;
-    child = that->myChildren.at( idx );
-  }
+  if ( idx >= 0 && idx < myChildren.count() )
+    child = myChildren.at( idx );
 
   return child;
 }
 
 /*!
-    Returns the level of the object in the data tree.
-    0 means that object is top-level.
-*/
+  \brief Get the object level in the tree structure.
+
+  Root object has level 0.
 
+  \return object level.
+*/
 int SUIT_DataObject::level() const
 {
   int lev = 0;
@@ -160,45 +223,67 @@ int SUIT_DataObject::level() const
 }
 
 /*!
-    Returns the next data object in the child list of the parent.
+  \brief Get the position of the data object in its parent's children list
+  \return data object position
 */
+int SUIT_DataObject::position() const
+{
+  return myParent ? myParent->childPos( this ) : 0;
+}
 
+/*!
+  \brief Get the next sibling data object in the children list.
+  \return child object or 0 if there is no next sibling
+  \sa prevBrother()
+*/
 SUIT_DataObject* SUIT_DataObject::nextBrother() const
 {
   return myParent ? myParent->childObject( myParent->childPos( this ) + 1 ) : 0;
 }
 
 /*!
-    Returns the previous data object in the child list of the parent.
+  \brief Get the previous sibling data object in the children list.
+  \return child object or 0 if there is no previous sibling
+  \sa nextBrother()
 */
-
 SUIT_DataObject* SUIT_DataObject::prevBrother() const
 {
   return myParent ? myParent->childObject( myParent->childPos( this ) - 1 ) : 0;
 }
 
 /*!
-    Returns 'true' if the object will delete children during destroying
+  \brief Get "auto-delete children" flag.
+  \return \c true if the object should delete all its children on destroying
+  \sa setAutoDeleteChildren()
 */
-
 bool SUIT_DataObject::autoDeleteChildren() const
 {
   return myAutoDel;
 }
 
 /*!
-    Specify should the object delete children during destroying
-*/
+  \brief Set "auto-delete children" flag.
+
+  If this flag is on (default), the object will delete
+  all its children on destroying.
 
+  \param on new flag value
+  \sa autoDeleteChildren()
+*/
 void SUIT_DataObject::setAutoDeleteChildren( const bool on )
 {
   myAutoDel = on;
 }
 
 /*!
-    Returns the list of the child objects. if 'rec' is 'true' then function get all sub children.
-*/
+  \brief Get all children.
 
+  If parameter \a rec is \c true then function collects all
+  the children recursively.
+
+  \param lst returning list of children
+  \param rec if \c true collect all children recursively
+*/
 void SUIT_DataObject::children( DataObjectList& lst, const bool rec ) const
 {
   for ( DataObjectList::const_iterator it = myChildren.begin(); it != myChildren.end(); ++it )
@@ -210,9 +295,15 @@ void SUIT_DataObject::children( DataObjectList& lst, const bool rec ) const
 }
 
 /*!
-    Returns the list of the child objects. if 'rec' is 'true' then function get all sub children.
-*/
+  \brief Get all children.
+  \override
+
+  If parameter \a rec is \c true then function collects all
+  the children recursively.
 
+  \param rec if \c true collect all children recursively
+  \return list of children
+*/
 DataObjectList SUIT_DataObject::children( const bool rec )
 {
   DataObjectList lst;
@@ -221,45 +312,56 @@ DataObjectList SUIT_DataObject::children( const bool rec )
 }
 
 /*!
-    Append new child object to the end of the children list
+  \brief Add new child object to the end of the children list.
+  \param obj child object being added
 */
-
-void SUIT_DataObject::appendChild( SUIT_DataObject* theObj ) 
+void SUIT_DataObject::appendChild( SUIT_DataObject* obj )
 {
-  insertChild( theObj, myChildren.count() );
+  insertChild( obj, myChildren.count() );
 }
 
 /*!
-    Insert new child object to the children list at specified position
+  \brief Insert new child object to the list of the children.
+  \param obj child object being added
+  \param position child position
 */
-
-void SUIT_DataObject::insertChild( SUIT_DataObject* theObj, int thePosition )
+void SUIT_DataObject::insertChild( SUIT_DataObject* obj, int position )
 {
-  if ( !theObj || myChildren.contains( theObj ) )
+  if ( !obj || myChildren.contains( obj ) )
     return;
 
-  int pos = thePosition < 0 ? myChildren.count() : thePosition;
-  myChildren.insert( qMin( pos, (int)myChildren.count() ), theObj );
-  theObj->setParent( this );
+  int pos = position < 0 ? myChildren.count() : position;
+  myChildren.insert( qMin( pos, (int)myChildren.count() ), obj );
+  obj->setParent( this );
+  signal()->emitInserted( obj, this );
 }
 
 /*!
-    Removes the specified child object reference.
+  \brief Remove the specified child object reference.
+  \param obj child object being removed
+  \param del if \c true, the child object is destroyed
 */
-
-void SUIT_DataObject::removeChild( SUIT_DataObject* theObj )
+void SUIT_DataObject::removeChild( SUIT_DataObject* obj, const bool del )
 {
-  if ( !theObj )
+  if ( !obj )
     return;
 
-  if ( myChildren.removeAll( theObj ) )
-    theObj->setParent( 0 );
+  if ( myChildren.removeAll( obj ) ) {
+    signal()->emitRemoved( obj, this );
+    obj->setParent( 0 );
+
+    if ( del )
+      obj->deleteLater();
+  }
 }
 
 /*!
-    Replaces the specified child object by another object.
+  \brief Replace the specified child object by another object.
+  \param src child object being replaced
+  \param trg new child object
+  \param del if \c true, the previous object is destroyed
+  \return \c true if the object has been replaced
 */
-
 bool SUIT_DataObject::replaceChild( SUIT_DataObject* src, SUIT_DataObject* trg, const bool del )
 {
   if ( !src || !trg )
@@ -286,9 +388,9 @@ bool SUIT_DataObject::replaceChild( SUIT_DataObject* src, SUIT_DataObject* trg,
 }
 
 /*!
-    Transfer the all children from specified object 'obj' to self.
+  \brief Change the parent for all children from specified object to this one.
+  \param obj object which children to be reparented
 */
-
 void SUIT_DataObject::reparentChildren( const SUIT_DataObject* obj )
 {
   if ( !obj )
@@ -301,170 +403,291 @@ void SUIT_DataObject::reparentChildren( const SUIT_DataObject* obj )
 }
 
 /*!
-    Set the parent object. Remove itself from current parent children
-    and append itself to the new parent children list.
+  \brief Get the parent object.
+  \return parent object or 0 if this is top-level item
 */
+SUIT_DataObject* SUIT_DataObject::parent() const
+{
+  return myParent;
+}
 
-void SUIT_DataObject::setParent( SUIT_DataObject* theParent )
+/*!
+  \brief Change the parent object.
+  \param p new parent object
+*/
+void SUIT_DataObject::setParent( SUIT_DataObject* p )
 {
-  if ( theParent == parent() )
+  if ( p == parent() )
     return;
 
   if ( parent() )
     parent()->removeChild( this );
 
-  myParent = theParent;
+  myParent = p;
 
   if ( parent() )
     parent()->appendChild( this );
 }
 
 /*!
-    Returns the parent object.
-*/
+  \brief Get data object name.
 
-SUIT_DataObject* SUIT_DataObject::parent() const
+  This method should be re-implemented in the subclasses.
+  Default implementation returns null string.
+
+  \return object name
+*/
+QString SUIT_DataObject::name() const
 {
-  return myParent;
+  return QString();
 }
 
-
 /*!
-    Connect to signal destroyed( SUIT_DataObject* ).
-*/
+  \brief Get object text data for the specified column.
 
-bool SUIT_DataObject::connect( QObject* reciever, const char* slot )
-{
-  if ( !reciever || !slot )
-    return false;
+  This method can be re-implemented in the subclasses.
+  Default implementation returns null string.
 
-  if ( !mySignal )
-    mySignal = new Signal( this );
+  Column with \a index = 0 (NameIdx) is supposed to be used
+  to get the object name (as it does the default implementation).
 
-  QObject::disconnect( mySignal, SIGNAL( destroyed( SUIT_DataObject* ) ), reciever, slot );
-  return QObject::connect( mySignal, SIGNAL( destroyed( SUIT_DataObject* ) ), reciever, slot );
+  \param index column index
+  \return object text data
+*/
+QString SUIT_DataObject::text( const int index ) const
+{
+  return index == NameIdx ? name() : QString();
 }
 
 /*!
-    Disconnect from signal destroyed( SUIT_DataObject* ).
-*/
+  \brief Get data object icon for the specified column.
 
-bool SUIT_DataObject::disconnect( QObject* reciever, const char* slot )
-{
-  if ( !reciever || !slot )
-    return false;
+  This method can be re-implemented in the subclasses.
+  Default implementation returns null pixmap.
 
-  if ( !mySignal )
-    return true;
+  The parameter \a index specifies the column number
+  (to display, for example, in the tree view widget).
 
-  return QObject::disconnect( mySignal, SIGNAL( destroyed( SUIT_DataObject* ) ), reciever, slot );
+  \param index column index
+  \return object icon for the specified column
+*/
+QPixmap SUIT_DataObject::icon( const int /*index*/ ) const
+{
+  return QPixmap();
 }
 
 /*!
-    Returns object name
-*/
+  \brief Get data object color for the specified column.
 
-void SUIT_DataObject::deleteLater()
+  This method can be re-implemented in the subclasses.
+  Default implementation returns null color.
+
+  The parameter \a index specifies the column number
+  (to display, for example, in the tree view widget).
+
+  \param role color role
+  \param index column index
+  \return object color for the specified column
+*/
+QColor SUIT_DataObject::color( const ColorRole /*role*/, const int /*index*/ ) const
 {
-  if ( !mySignal )
-    mySignal = new Signal( this );
-  
-  mySignal->emitSignal();
-  mySignal->deleteLater();
+  return QColor();
 }
 
 /*!
-    Returns object name
-*/
+  \brief Get data object tooltip for the specified column.
 
-QString SUIT_DataObject::name() const
+  This method can be re-implemented in the subclasses.
+  Default implementation returns null string.
+
+  The parameter \a index specifies the column number
+  (to display, for example, in the tree view widget).
+
+  \param index column index
+  \return object tooltip for the specified column
+*/
+QString SUIT_DataObject::toolTip( const int /*index*/ ) const
 {
-  return QString::null;
+  return QString();
 }
 
 /*!
-    Returns object icon
-*/
+  \brief Get data object status tip for the specified column.
+
+  This method can be re-implemented in the subclasses.
+  Default implementation returns null string.
+
+  The parameter \a index specifies the column number
+  (to display, for example, in the tree view widget).
 
-QPixmap SUIT_DataObject::icon() const
+  \param index column index
+  \return object status tip for the specified column
+*/
+QString SUIT_DataObject::statusTip( const int /*index*/ ) const
 {
-  return QPixmap();
+  return QString();
 }
 
 /*!
-    Returns object text
-*/
+  \brief Get data object "what's this" information for the
+         specified column.
+
+  This method can be re-implemented in the subclasses.
+  Default implementation returns null string.
 
-QString SUIT_DataObject::text( const int ) const
+  The parameter \a index specifies the column number
+  (to display, for example, in the tree view widget).
+
+  \param index column index
+  \return object "what's this" information for the specified column
+*/
+QString SUIT_DataObject::whatsThis( const int /*index*/ ) const
 {
-  return QString::null;
+  return QString();
 }
 
 /*!
-    Returns object color
-*/
+  \brief Get data object font for the specified column.
+
+  This method can be re-implemented in the subclasses.
+  Default implementation returns application default font.
 
-QColor SUIT_DataObject::color( const ColorRole ) const
+  The parameter \a index specifies the column number
+  (to display, for example, in the tree view widget).
+
+  \param index column index
+  \return object font for the specified column
+*/
+QFont SUIT_DataObject::font( const int /*index*/ ) const
 {
-  return QColor();
+  return QFont();
 }
 
 /*!
-    Returns object tool tip
-*/
+  \brief Get data object text alignment for the specified column.
 
-QString SUIT_DataObject::toolTip() const
+  This method can be re-implemented in the subclasses.
+  Default implementation returns default alignment which
+  is Qt:AlignLeft.
+
+  The parameter \a index specifies the column number
+  (to display, for example, in the tree view widget).
+
+  \param index column index
+  \return object text alignment flags for the specified column
+*/
+int SUIT_DataObject::alignment( const int /*index*/ ) const
 {
-  return QString::null;
+  return Qt::AlignLeft;
 }
 
 /*!
-    Returns 'true' if it is possible to drag this object
-*/
+  \brief Check if the object is draggable.
 
+  This method can be re-implemented in the subclasses.
+  Default implementation returns \c false (all objects could not be dragged).
+
+  \return \c true if it is possible to drag this object
+*/
 bool SUIT_DataObject::isDragable() const
 {
   return false;
 }
 
 /*!
-    Returns 'true' if it is possible to drop an object "obj" to this object.
+  \brief Check if the drop operation fo this object is possible.
+
+  This method can be re-implemented in the subclasses.
+  Default implementation returns \c false (drop operation is not allowed).
+
+  \param obj object being dropped
+  \return \c true if it is possible to drop an object \c obj
+          to this object
 */
 
-bool SUIT_DataObject::isDropAccepted( SUIT_DataObject* )
+bool SUIT_DataObject::isDropAccepted( SUIT_DataObject* /*obj*/ )
 {
   return false;
 }
 
 /*!
-    Returns type of check possibility.
-*/
+  \brief Check if this object is enabled.
+
+  This method can be re-implemented in the subclasses.
+  Default implementation returns \c true (all objects are enabled).
 
-SUIT_DataObject::CheckType SUIT_DataObject::checkType() const
+  \return \c true if the user can interact with the item
+*/
+bool SUIT_DataObject::isEnabled() const
 {
-  return None;
+  return true;
 }
 
 /*!
-    Returns the checked state of the object.
+  \brief Check if this object is selectable.
+
+  This method can be re-implemented in the subclasses.
+  Default implementation returns \c true (all objects are selectable).
+
+  \return \c true if the item can be selected
 */
+bool SUIT_DataObject::isSelectable() const
+{
+  return true;
+}
+
+/*!
+  \brief Check if this object is checkable for the specified column.
 
-bool SUIT_DataObject::isOn() const
+  This method can be re-implemented in the subclasses.
+  Default implementation returns \c false (all objects are not checkable).
+
+  \param index column index
+  \return \c true if the item can be checked or unchecked by the user
+  \sa isOn(), setOn()
+*/
+bool SUIT_DataObject::isCheckable( const int /*index*/ ) const
 {
-  return myCheck;
+  return false;
 }
 
 /*!
-    Sets the checked state of the object.
+  \brief Get the checked state of the object (if it is checkable)
+  for the specified column.
+
+  Default implementation supports the checked state for the first
+  ("Name") column only.
+
+  \param index column index
+  \return checked state of the object for the specified column
+  \sa setOn(), isCheckable()
 */
+bool SUIT_DataObject::isOn( const int index ) const
+{
+  return index == NameIdx && myCheck;
+}
+
+/*!
+  \brief Set the checked state of the object (if it is checkable)
+  for the specified column.
+
+  Default implementation supports the checked state for the first
+  ("Name") column only.
 
-void SUIT_DataObject::setOn( const bool on )
+  \param on new checked state of the object for the specified column
+  \param index column index
+  \sa isOn(), isCheckable()
+*/
+void SUIT_DataObject::setOn( const bool on, const int index )
 {
-  myCheck = on;
+  if ( index == NameIdx )
+    myCheck = on;
 }
 
 /*!
-    \return the opened state of the object (used in Object Browser).
+  \brief Get the "opened" state of the object.
+  \return "opened" state of the object
+  \sa setOpen()
 */
 bool SUIT_DataObject::isOpen() const
 {
@@ -472,7 +695,9 @@ bool SUIT_DataObject::isOpen() const
 }
 
 /*!
-    Sets the opened state of the object (used in Object Browser).
+  \brief Set the "opened" state of the object.
+  \param on new "opened" state of the object
+  \sa isOpen()
 */
 void SUIT_DataObject::setOpen( const bool on )
 {
@@ -480,62 +705,257 @@ void SUIT_DataObject::setOpen( const bool on )
 }
 
 /*!
-    Returns object personal indentification key.
+  \brief Check if the specified column supports custom sorting.
+
+  This method can be re-implemented in the subclasses.
+  Default implementation returns false ("Name" column does not require
+  custom sorting).
+
+  \param index column index
+  \return \c true if column sorting should be customized
+  \sa compare()
 */
+bool SUIT_DataObject::customSorting( const int /*index*/ ) const
+{
+  return false;
+}
 
+/*!
+  \brief Compares data from two items for sorting purposes.
+
+  This method can be re-implemented in the subclasses.
+  Default implementation returns false ("Name" column does not require
+  custom sorting).
+
+  This method is called only for those columns for which customSorting()
+  method returns \c true.
+
+  \param left first data to compare
+  \param right second data to compare
+  \param index column index
+  \return result of the comparison
+  \sa customSorting()
+*/
+bool SUIT_DataObject::compare( const QVariant& /*left*/, const QVariant& /*right*/,
+                              const int /*index*/ ) const
+{
+  return false;
+}
+
+/*!
+  \brief Get the object unique indentification key.
+
+  This method can be re-implemented in the subclasses.
+  Default implementation returns 0.
+
+  \return object key
+*/
 SUIT_DataObjectKey* SUIT_DataObject::key() const
 {
   return 0;
 }
 
 /*!
-   Dump this data object and its children to cout
+  \brief Get global signal handler.
+  \return the only instance of the signal handler
+*/
+SUIT_DataObject::Signal* SUIT_DataObject::signal()
+{
+  if ( !mySignal )
+    mySignal = new Signal();
+  return mySignal;
+}
+
+/*!
+  \brief Connect to the signal handlerx
+  \param sig signal name
+  \param reciever signal receiver object
+  \param slot slot name
+  \return \c true if connection is successfull
+*/
+bool SUIT_DataObject::connect( const char* sig, QObject* reciever, const char* slot )
+{
+  if ( !reciever || !slot )
+    return false;
+
+  signal()->disconnect( signal(), sig, reciever, slot );
+  return signal()->connect( signal(), sig, reciever, slot );
+}
+
+/*!
+  \brief Disconnect from the signal handler
+  \param sig signal name
+  \param reciever signal receiver object
+  \param slot slot name
+  \return \c true if disconnection is successfull
+*/
+bool SUIT_DataObject::disconnect( const char* sig, QObject* reciever, const char* slot )
+{
+  if ( !reciever || !slot )
+    return false;
+  return signal()->disconnect( signal(), sig, reciever, slot );
+}
+
+/*!
+  \brief Schedule this object for the late deleting.
+
+  The object will be deleted when control returns to the event loop.
+  Note that entering and leaving a new event loop (e.g., by opening
+  a modal dialog) will not perform the deferred deletion; for the object
+  to be deleted, the control must return to the event loop from which
+  deleteLater() was called.
+*/
+void SUIT_DataObject::deleteLater()
+{
+  if ( parent() )
+    parent()->removeChild( this, false ); // to avoid infinite loop!
+  signal()->deleteLater( this );
+}
+
+/*!
+  \brief Dump the object tree recursively to the standard output.
+  \param indent current indentation level
 */
 void SUIT_DataObject::dump( const int indent ) const
 {
-  QString strIndent = QString().fill( ' ', indent ); // indentation string 
+  QString strIndent = QString().fill( ' ', indent ); // indentation string
   printf( "%s%s\n", strIndent.toLatin1().data(), name().toLatin1().data() );
   for ( DataObjectList::const_iterator it = myChildren.begin(); it != myChildren.end(); ++it )
     (*it)->dump( indent + 2 );
 }
 
 /*!
-  Class: SUIT_DataObject::Signal [Internal]
+  \class SUIT_DataObject::Signal
+  \brief Watcher class, responsible for the emitting signals on behalf of
+  the data objects.
+
+  SUIT_DataObject class does not inherit from QObject for the performance
+  reasons, so it can not use signals/slots mechanism directly.
+  Instead it uses the only Signal object to emit the signals when the data
+  object is created, destroyed, inserted to the parent object or removed
+  from it.
+
+  If some object needs to handle, for example, data object destroying, it can
+  use SUIT_DataObject::signal() method to connect the signal:
+  \code
+  MyHandler* h = new MyHandler();
+  h->connect( SUIT_DataObject::signal(), SIGNAL(destroyed(SUIT_DataObject*)),
+              h, SLOT(onDestroyed(SUIT_DataObject*)) );
+  \endcode
+  The same can be done by using static method SUIT_DataObject::connect().
+  For example,
+  \code
+  MyHandler* h = new MyHandler();
+  SUIT_DataObject::connect( SIGNAL(destroyed(SUIT_DataObject*)),
+                            h, SLOT(onDestroyed(SUIT_DataObject*)));
+  \endcode
 */
 
-SUIT_DataObject::Signal::Signal( SUIT_DataObject* o )
-: QObject(),
-myOwner( o )
+/*!
+  \brief Constructor.
+*/
+SUIT_DataObject::Signal::Signal()
+: QObject()
 {
 }
 
 /*!
-  Destructor.
+  \brief Destructor.
+
+  Destroys data object which are scheduled for the deleting with the deleteLater().
 */
 SUIT_DataObject::Signal::~Signal()
 {
-  SUIT_DataObject* o = myOwner;
-  myOwner = 0;
-  if ( o )
-  {
-    o->mySignal = 0;
-    delete o;
+  for ( DataObjectList::Iterator it = myDelLaterObjects.begin();
+       it != myDelLaterObjects.end(); ++it ) {
+    delete *it;
+  }
+  myDelLaterObjects.clear();
+}
+
+/*!
+  \brief Emit signal about data object creation.
+  \param object data object being created
+*/
+void SUIT_DataObject::Signal::emitCreated( SUIT_DataObject* object )
+{
+  if ( object )
+    emit created( object );
+}
+
+/*!
+  \brief Emit signal about data object destroying.
+  \param object data object being destroyed
+*/
+void SUIT_DataObject::Signal::emitDestroyed( SUIT_DataObject* object )
+{
+  if ( object ) {
+    if ( myDelLaterObjects.contains( object ) )
+      // object is being destroyed after calling deleteLater():
+      // the signal has been already emitted from deleteLater()
+      // we should avoid repeating of the object destroying from
+      // the Signal destructor
+      myDelLaterObjects.removeAll( object );
+    else
+      // object is being destroyed directly or via deleteLater()
+      emit destroyed( object );
   }
 }
 
 /*!
-  Set owner \a o.
+  \brief Emit signal about data object adding to the parent data object.
+  \param object data object being added
+  \param parent parent data object
 */
-void SUIT_DataObject::Signal::setOwner( SUIT_DataObject* o )
+void SUIT_DataObject::Signal::emitInserted( SUIT_DataObject* object, SUIT_DataObject* parent )
 {
-  myOwner = o;
+  emit( inserted( object, parent ) );
 }
 
 /*!
-  emit signal destroed owner.
+  \brief Emit signal about data object removed from the parent data object.
+  \param object data object being removed
+  \param parent parent data object
 */
-void SUIT_DataObject::Signal::emitSignal()
+void SUIT_DataObject::Signal::emitRemoved( SUIT_DataObject* object, SUIT_DataObject* parent )
 {
-  if ( myOwner )
-    emit destroyed( myOwner );
+  emit( removed( object, parent ) );
 }
+
+/*!
+  \brief Schedule data object for the late deleting.
+  \param object data object to be deleted later
+*/
+void SUIT_DataObject::Signal::deleteLater( SUIT_DataObject* object )
+{
+  if ( !myDelLaterObjects.contains( object ) ) {
+    emitDestroyed( object );
+    myDelLaterObjects.append( object );
+  }
+}
+
+/*!
+  \fn void SUIT_DataObject::Signal::created( SUIT_DataObject* object );
+  \brief Emitted when data object is created.
+  \param object data object being created
+*/
+
+/*!
+  \fn void SUIT_DataObject::Signal::destroyed( SUIT_DataObject* object );
+  \brief Emitted when data object is destroyed.
+  \param object data object being destroyed
+*/
+
+/*!
+  \fn void SUIT_DataObject::Signal::inserted( SUIT_DataObject* object, SUIT_DataObject* parent );
+  \brief Emitted when data object is inserted to the parent data object.
+  \param object data object being created
+  \param parent parent data object
+*/
+
+/*!
+  \fn void SUIT_DataObject::Signal::removed( SUIT_DataObject* object, SUIT_DataObject* parent );
+  \brief Emitted when data object is removed from the parent data object.
+  \param object data object being removed
+  \param parent parent data object
+*/
index 1f479192c273e37dd1595deef9747b5d7f0d6934..9f79ac9f1b523ec55b2ab2361c018ea33296096a 100755 (executable)
@@ -16,6 +16,9 @@
 //
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
+// File   : SUIT_DataObject.h
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+//
 
 #ifndef SUIT_DATAOBJECT_H
 #define SUIT_DATAOBJECT_H
@@ -26,6 +29,7 @@
 #include <QObject>
 #include <QString>
 #include <QPixmap>
+#include <QFont>
 
 class SUIT_DataObject;
 class SUIT_DataObjectKey;
@@ -36,18 +40,25 @@ typedef QList<SUIT_DataObject*> DataObjectList;
 #pragma warning( disable:4251 )
 #endif
 
-/*!
-  \class SUIT_DataObject
-  Data Object represents uniform data tree structure recommended to use in SUIT-based applications
-  Many of standard classes (DataModel,ObjectBrowser) deal with SUIT_DataObjects
-*/
 class SUIT_EXPORT SUIT_DataObject  
 {
 public:
   class Signal;
 
-  typedef enum { None, RadioButton, CheckBox } CheckType;
-  typedef enum { Text, Base, Foreground, Background, Highlight, HighlightedText } ColorRole;
+  //! Color role
+  typedef enum { 
+    Text,              //!< editor foreground (text) color
+    Base,              //!< editor background color
+    Foreground,        //!< foreground (text) color
+    Background,        //!< background color
+    Highlight,         //!< highlight background color
+    HighlightedText    //!< highlighted foreground (text) color
+  } ColorRole;
+
+  //! Column index
+  enum { 
+    NameIdx            //!< name column
+  };
 
   SUIT_DataObject( SUIT_DataObject* = 0 );
   virtual ~SUIT_DataObject();
@@ -56,10 +67,16 @@ public:
   SUIT_DataObject*            lastChild() const;
   SUIT_DataObject*            firstChild() const;
 
+  virtual int                 columnCount() const;
+  virtual QString             columnTitle( const int = NameIdx ) const;
+  virtual QPixmap             columnIcon( const int = NameIdx ) const;
+  virtual bool                appropriate( const int = NameIdx ) const;
+
   int                         childCount() const;
   int                         childPos( const SUIT_DataObject* ) const;
   SUIT_DataObject*            childObject( const int ) const;
   int                         level() const;
+  int                         position() const;
 
   SUIT_DataObject*            nextBrother() const;
   SUIT_DataObject*            prevBrother() const;
@@ -71,81 +88,95 @@ public:
   virtual DataObjectList      children( const bool = false );
   
   void                        appendChild( SUIT_DataObject* );
-  virtual void                removeChild( SUIT_DataObject* );
-  virtual void                insertChild( SUIT_DataObject*, int thePosition );
+  virtual void                insertChild( SUIT_DataObject*, int );
+  virtual void                removeChild( SUIT_DataObject*, const bool = false );
   bool                        replaceChild( SUIT_DataObject*, SUIT_DataObject*, const bool = false );
 
   void                        reparentChildren( const SUIT_DataObject* );
 
-  virtual QString             text( const int ) const;
-  virtual QColor              color( const ColorRole ) const;
-
-  virtual QString             name() const;
-  virtual QPixmap             icon() const;
-  virtual QString             toolTip() const;
-
   virtual SUIT_DataObject*    parent() const;
   virtual void                setParent( SUIT_DataObject* );
 
+  virtual QString             name() const;
+  virtual QString             text( const int = NameIdx ) const;
+  virtual QPixmap             icon( const int = NameIdx ) const;
+  virtual QColor              color( const ColorRole, const int = NameIdx ) const;
+  virtual QString             toolTip( const int = NameIdx ) const;
+  virtual QString             statusTip( const int = NameIdx ) const;
+  virtual QString             whatsThis( const int = NameIdx ) const;
+  virtual QFont               font( const int = NameIdx ) const;
+  virtual int                 alignment( const int = NameIdx ) const;
+
   virtual bool                isDragable() const;
   virtual bool                isDropAccepted( SUIT_DataObject* obj );
 
-  virtual CheckType           checkType() const;
+  virtual bool                isEnabled() const;
+  virtual bool                isSelectable() const;
+  virtual bool                isCheckable( const int = NameIdx ) const;
 
-  virtual bool                isOn() const;
-  virtual void                setOn( const bool );
+  virtual bool                isOn( const int = NameIdx ) const;
+  virtual void                setOn( const bool, const int = NameIdx );
 
   virtual bool                isOpen() const;
   virtual void                setOpen( const bool );
 
+  virtual bool                customSorting( const int = NameIdx ) const;
+  virtual bool                compare( const QVariant&, const QVariant&, 
+                                      const int = NameIdx ) const;
+
   virtual SUIT_DataObjectKey* key() const;
 
-  bool                        connect( QObject*, const char* );
-  bool                        disconnect( QObject*, const char* );
+  static Signal*              signal();
+  static bool                 connect( const char*, QObject*, const char* );
+  static bool                 disconnect( const char*, QObject*, const char* );
 
   void                        deleteLater();
-  
+
   void                        dump( const int indent = 2 ) const; // dump to cout
 
 private:
   SUIT_DataObject*            myParent;
   bool                        myOpen;
   bool                        myCheck;
-  Signal*                     mySignal;
   bool                        myAutoDel;
   DataObjectList              myChildren;
 
+  static Signal*              mySignal;
+
   friend class SUIT_DataObject::Signal;
   friend class SUIT_DataObjectIterator;
 };
 
-/*!
-  \class SUIT_DataObject::Signal
-  Auxiliary class providing functionality to use signals of data object state change
-  SUIT_DataObject cannot have signals, because it isn't QObject, but
-  methods connect/disconnect of SUIT_DataObject with help of this it is possible
-  to emulate Qt signal processing
-*/
-class SUIT_DataObject::Signal : public QObject
+class SUIT_EXPORT SUIT_DataObject::Signal : public QObject
 {
   Q_OBJECT
 
 public:
-  Signal( SUIT_DataObject* );
+  Signal();
   virtual ~Signal();
 
-  void                        emitSignal();
-  void                        setOwner( SUIT_DataObject* o );
+private:
+  void emitCreated( SUIT_DataObject* );
+  void emitDestroyed( SUIT_DataObject* );
+  void emitInserted( SUIT_DataObject*, SUIT_DataObject* );
+  void emitRemoved( SUIT_DataObject*, SUIT_DataObject* );
+
+  void deleteLater( SUIT_DataObject* );
 
 signals:
-  void                        destroyed( SUIT_DataObject* );
+  void created( SUIT_DataObject* );
+  void destroyed( SUIT_DataObject* );
+  void inserted( SUIT_DataObject*, SUIT_DataObject* );
+  void removed( SUIT_DataObject*, SUIT_DataObject* );
+
+  friend class SUIT_DataObject;
 
 private:
-  SUIT_DataObject*            myOwner;
+  DataObjectList myDelLaterObjects;
 };
 
 #ifdef WIN32
 #pragma warning( default:4251 )
 #endif
 
-#endif
+#endif  // SUIT_DATAOBJECT_H
diff --git a/src/SUIT/SUIT_TreeModel.cxx b/src/SUIT/SUIT_TreeModel.cxx
new file mode 100755 (executable)
index 0000000..665bb6c
--- /dev/null
@@ -0,0 +1,1431 @@
+// 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
+//
+// File:   SUIT_TreeModel.cxx
+// Author: Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+//
+
+#include "SUIT_TreeModel.h"
+#include "SUIT_TreeSync.h"
+#include "SUIT_DataObject.h"
+
+#include <QApplication>
+
+/*!
+  \class SUIT_TreeModel::TreeItem
+  \brief Internal class used for tree view synchronizaton with data object tree.
+  \internal
+*/
+
+class SUIT_TreeModel::TreeItem
+{
+public:
+  TreeItem( SUIT_DataObject* obj, TreeItem* parent = 0, TreeItem* after = 0 );
+  ~TreeItem();
+
+  void                  insertChild( TreeItem* child, TreeItem* after = 0 );
+  void                  removeChild( TreeItem* child );
+  SUIT_DataObject*      dataObject() const;
+  TreeItem*             parent() const;
+  int                   position() const;
+  int                   childCount() const;
+  TreeItem*             child( const int i );
+  QList<TreeItem*>      children() const;
+  TreeItem*             nextSibling() const;
+  TreeItem*             prevSibling() const;
+  
+private:
+  TreeItem*             myParent;
+  QList<TreeItem*>      myChildren;
+  SUIT_DataObject*      myObj;
+};
+
+/*!
+  \brief Constructor.
+  \internal
+  \param obj data object
+  \param parent parent item
+  \param after tree item after each this one should be inserted
+*/
+SUIT_TreeModel::TreeItem::TreeItem( SUIT_DataObject*          obj, 
+                                   SUIT_TreeModel::TreeItem* parent,
+                                   SUIT_TreeModel::TreeItem* after )
+: myParent( parent ),
+  myObj( obj )
+{
+  // Add <this> to the parent's children list
+  if ( myParent )
+    myParent->insertChild( this, after );
+}
+
+/*!
+  \brief Destructor. Deletes all child items recursively.
+  \internal
+*/
+SUIT_TreeModel::TreeItem::~TreeItem()
+{
+  // Ensure that all children are deleted;
+  // each child removes itself from the children list
+  while( myChildren.count() )
+    delete myChildren.at( 0 );
+
+  // Remove this item from the parent's children list
+  if ( myParent )
+    myParent->removeChild( this );
+}
+
+/*!
+  \brief Insert child item.
+  \internal
+  \param child child item being inserted
+  \param after tree item after each \a child should be inserted
+*/
+void SUIT_TreeModel::TreeItem::insertChild( SUIT_TreeModel::TreeItem* child, 
+                                           SUIT_TreeModel::TreeItem* after )
+{
+  if ( !child )
+    return;
+
+  int index = after ? myChildren.indexOf( after ) + 1 : 0;
+  myChildren.insert( index, child );
+}
+
+/*!
+  \brief Remove child item.
+  \internal
+  \param child child item being removed
+*/
+void SUIT_TreeModel::TreeItem::removeChild( SUIT_TreeModel::TreeItem* child )
+{
+  if ( !child )
+    return;
+  myChildren.removeAll( child );
+}
+
+/*!
+  \brief Get data object.
+  \internal
+  \return data object this item is associated to
+*/
+SUIT_DataObject* SUIT_TreeModel::TreeItem::dataObject() const
+{
+  return myObj;
+}
+
+/*!
+  \brief Get parent item.
+  \internal
+  \return parent item
+*/
+SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::parent() const
+{
+  return myParent;
+}
+
+/*!
+  \brief Get position of this item in its parent's children list.
+  \internal
+  \return item position
+*/
+int SUIT_TreeModel::TreeItem::position() const
+{
+  return myParent->myChildren.indexOf( (TreeItem*)this );
+}
+
+/*!
+  \brief Get number of child items.
+  \internal
+  \return number of children
+*/
+int SUIT_TreeModel::TreeItem::childCount() const
+{
+  return myChildren.count();
+}
+
+/*!
+  \brief Get child item by specified index.
+  \internal
+  \param i child item index
+  \return child item or 0 if \a i is out of range
+*/
+SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::child( const int i )
+{
+  return i >= 0 && i < myChildren.count() ? myChildren.at( i ) : 0;
+}
+
+/*!
+  \brief Get all child items.
+  \internal
+  \return list of child items
+*/
+QList<SUIT_TreeModel::TreeItem*> SUIT_TreeModel::TreeItem::children() const
+{
+  return myChildren;
+}
+
+/*!
+  \brief Get next sibling item.
+  \internal
+  \return next sibling item or 0 if there are no any
+*/
+SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::nextSibling() const
+{
+  return parent() ? parent()->child( position()+1 ) : 0;
+}
+
+/*!
+  \brief Get previous sibling item.
+  \internal
+  \return previous sibling item or 0 if there are no any
+*/
+SUIT_TreeModel::TreeItem* SUIT_TreeModel::TreeItem::prevSibling() const
+{
+  return parent() ? parent()->child( position()-1 ) : 0;
+}
+
+/*!
+  \class SUIT_TreeModel::TreeSync
+  \brief Functor class for synchronizing data tree and tree model 
+         when the data tree is changed outside the model.
+  \internal
+*/
+
+class SUIT_TreeModel::TreeSync
+{
+public:
+  TreeSync( SUIT_TreeModel* );
+  bool              isEqual( const ObjPtr&, const ItemPtr& ) const;
+  ObjPtr            nullSrc() const;
+  ItemPtr           nullTrg() const;
+  ItemPtr           createItem( const ObjPtr&, const ItemPtr&, const ItemPtr& ) const;
+  void              updateItem( const ObjPtr&, const ItemPtr& ) const;
+  void              deleteItemWithChildren( const ItemPtr& ) const;
+  QList<ObjPtr>     children( const ObjPtr& ) const;
+  QList<ItemPtr>    children( const ItemPtr& ) const;
+  ItemPtr           parent( const ItemPtr& ) const;
+private:
+  bool              needUpdate( const ItemPtr& ) const;
+  SUIT_TreeModel*   myModel;
+};
+
+/*!
+  \brief Constructor.
+  \internal
+  \param model tree model
+*/
+SUIT_TreeModel::TreeSync::TreeSync( SUIT_TreeModel* model )
+: myModel( model )
+{
+}
+
+/*!
+  \brief Check if item corresponds to the specified data object.
+  \internal
+  \param obj data object
+  \param item tree item 
+  \return \c true if item corresponds to the data object
+*/
+bool SUIT_TreeModel::TreeSync::isEqual( const ObjPtr& obj, const ItemPtr& item ) const
+{
+  bool isRoot = obj == myModel->root() && item == myModel->rootItem(),
+       isEq   = obj && item && item->dataObject() == obj;
+  return isRoot || ( !obj && !item ) || isEq;
+}
+
+/*!
+  \brief Get null data object.
+  \internal
+  \return null data object
+*/
+SUIT_TreeModel::ObjPtr SUIT_TreeModel::TreeSync::nullSrc() const
+{
+  return 0;
+}
+
+/*!
+  \brief Get null tree item.
+  \internal
+  \return null tree item
+*/
+SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::nullTrg() const
+{
+  return 0;
+}
+
+/*!
+  \brief Create an item corresponding to the specified data object.
+  \internal
+  \param obj data object
+  \param parent parent tree item
+  \param after tree item after each new one should be inserted
+  \return created item
+*/
+SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::createItem( const ObjPtr&  obj,
+                                                             const ItemPtr& parent, 
+                                                             const ItemPtr& after ) const
+{
+  ItemPtr item = myModel ? myModel->createItem( obj, parent, after ) : 0;
+
+  // Additional actions that can't be performed by the model, e.g. expanded state
+  if( item && myModel->updater() )
+    myModel->updater()->update( obj );
+  return item;
+}
+
+/*!
+  \brief Update tree item.
+  \internal
+  \param obj reference data object
+  \param item tree item to be updated
+*/
+void SUIT_TreeModel::TreeSync::updateItem( const ObjPtr& obj, const ItemPtr& item ) const
+{
+  if ( item && needUpdate( item ) ) 
+    myModel->updateItem( item );
+
+  // SUIT_TreeUpdater class performs additional update of a tree view,
+  // since the view is not available from inside a model
+  if( obj && myModel->updater() )
+    myModel->updater()->update( obj );
+}
+
+/*!
+  \brief Delete item with all children recursively.
+  \internal
+  \param item tree item
+*/
+void SUIT_TreeModel::TreeSync::deleteItemWithChildren( const ItemPtr& item ) const
+{
+  // NOTE: item is deleted inside removeItem()!
+  myModel->removeItem( item );
+}
+
+/*!
+  \brief Get all the children of the specified data object.
+  \internal
+  \param obj data object
+  \return list of the children
+*/
+QList<SUIT_TreeModel::ObjPtr> SUIT_TreeModel::TreeSync::children( const ObjPtr& obj ) const
+{
+  QList<ObjPtr> ch;
+  if ( obj )
+    ch = obj->children();
+  return ch;
+}
+
+/*!
+  \brief Get all the children of the specified tree item.
+  \internal
+  \param item tree item
+  \return list of the children
+*/
+QList<SUIT_TreeModel::ItemPtr> SUIT_TreeModel::TreeSync::children( const ItemPtr& item ) const
+{
+  QList<ItemPtr> ch;
+  if ( item ) 
+    ch = item->children();
+  return ch;
+}
+
+/*!
+  \brief Get item which is the parent for the specified item.
+  \internal
+  \param item tree item
+  \return parent item
+*/
+SUIT_TreeModel::ItemPtr SUIT_TreeModel::TreeSync::parent( const ItemPtr& item ) const
+{
+  return item ? item->parent() : 0;
+}
+
+/*!
+  \brief Check if the tree item needs updating.
+  \internal
+  \param item tree item to be checked
+  \return \c true if item needs updating
+
+  \todo finalize this method
+*/
+bool SUIT_TreeModel::TreeSync::needUpdate( const ItemPtr& item ) const
+{
+  bool update = false;
+  if ( item ) {
+    SUIT_DataObject* obj = item->dataObject();
+    if ( obj ) {
+      // TODO: find simplified way to check if an item is not up-to-date:
+      // - use check-sum of various item data
+      // - use "LastModified" time stamp in data objects and tree items - hardly possible, for sometimes data objects do not know that data changes...
+      // ...
+      update = true; // TEMPORARY!!!
+      // 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;
+}
+
+/*!
+  \class SUIT_TreeModel
+  \brief Implementation of the model/view API based on the tree of SUIT_DataObject class
+  instances.
+
+  The SUIT_TreeModel class does not support insertion/removal of rows. It is synchronized 
+  automatically with the tree of data objects used by SUIT-based applications to 
+  expose their data in a hierarchical form to the user.
+*/
+
+/*!
+  \brief Constructor.
+  \param parent parent object
+*/
+SUIT_TreeModel::SUIT_TreeModel( QObject* parent )
+: QAbstractItemModel( parent ),
+  myRoot( 0 ),
+  myRootItem( 0 ),
+  myAutoDeleteTree( false ),
+  myAutoUpdate( true ),
+  myUpdater( 0 )
+{
+  initialize();
+}
+
+/*!
+  \brief Constructor.
+  \param root root data object
+  \param parent parent object
+*/
+SUIT_TreeModel::SUIT_TreeModel( SUIT_DataObject* root, QObject* parent )
+: QAbstractItemModel( parent ),
+  myRoot( root ),
+  myRootItem( 0 ),
+  myAutoDeleteTree( false ),
+  myAutoUpdate( true ),
+  myUpdater( 0 )
+{
+  initialize();
+}
+
+/*!
+  \brief Destructor
+*/
+SUIT_TreeModel::~SUIT_TreeModel()
+{
+  if ( autoDeleteTree() ) {
+    SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
+                                this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
+    SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
+                                this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
+    delete myRoot;
+  }
+
+  delete myUpdater;
+  delete myRootItem;
+}
+
+/*!
+  \brief Get data tree root object.
+  \return data tree root
+  \sa setRoot()
+*/
+SUIT_DataObject* SUIT_TreeModel::root() const
+{
+  return myRoot;
+}
+
+/*!
+  \brief Set data tree root object.
+  \param r new data tree root
+  \sa root()
+*/
+void SUIT_TreeModel::setRoot( SUIT_DataObject* r )
+{
+  if ( root() == r )
+    return;
+
+  if ( autoDeleteTree() ) {
+    SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
+                                this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
+    SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
+                                this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
+    delete myRoot;
+  }
+
+  myRoot = r;
+
+  //initialize();
+  reset();
+}
+
+/*!
+  \brief Get data for the specified model index and data role.
+  \param index model index
+  \param role data role
+  \return requested data
+  \sa setData()
+*/
+QVariant SUIT_TreeModel::data( const QModelIndex& index, int role ) const
+{
+  if ( !index.isValid() )
+    return QVariant();
+
+  SUIT_DataObject* obj = object( index );
+
+  QColor c;
+  QVariant val;
+
+  if ( obj ) {
+    switch ( role ) {
+    case DisplayRole:
+      // data object text for the specified column
+      val = obj->text( index.column() ); 
+      break;
+    case DecorationRole:
+      // data object icon for the specified column
+      val = obj->icon( index.column() ); 
+      break;
+    case ToolTipRole:
+      // data object tooltip for the specified column
+      val = obj->toolTip( index.column() ); 
+      break;
+    case StatusTipRole:
+      // data object status tip for the specified column
+      val = obj->statusTip( index.column() ); 
+      break;
+    case WhatsThisRole:
+      // data object what's this info for the specified column
+      val = obj->whatsThis( index.column() ); 
+      break;
+    case FontRole:
+      // data object font for the specified column
+      val = obj->font( index.column() ); 
+      break;
+    case TextAlignmentRole:
+      // data object text alignment for the specified column
+      val = obj->alignment( index.column() ); 
+      break;
+    case BackgroundRole:
+      // data background color for the specified column
+      c = obj->color( SUIT_DataObject::Background, index.column() );
+      if ( !c.isValid() ) // default value
+       c = QApplication::palette().color( QPalette::Base );
+      val = c; 
+      break;
+    case ForegroundRole:
+      // data foreground (text) color for the specified column
+      c = obj->color( SUIT_DataObject::Foreground, index.column() );
+      if ( !c.isValid() ) // default value
+       c = QApplication::palette().color( QPalette::Foreground );
+      val = c; 
+      break;
+    case BaseColorRole:
+      // editor background color for the specified column
+      c = obj->color( SUIT_DataObject::Base, index.column() );
+      if ( !c.isValid() ) // default value
+       c = QApplication::palette().color( QPalette::Base );
+      val = c; 
+      break;
+    case TextColorRole:
+      // editor foreground (text) color for the specified column
+      c = obj->color( SUIT_DataObject::Text, index.column() );
+      if ( !c.isValid() ) // default value
+       c = QApplication::palette().color( QPalette::Text );
+      val = c; 
+      break;
+    case HighlightRole:
+      // adta object highlighted background color for the specified column
+      c = obj->color( SUIT_DataObject::Highlight, index.column() );
+      if ( !c.isValid() ) // default value
+       c = QApplication::palette().color( QPalette::Highlight );
+      val = c; 
+      break;
+    case HighlightedTextRole:
+      // data object highlighted foreground (text) color for the specified column
+      c = obj->color( SUIT_DataObject::HighlightedText, index.column() );
+      if ( !c.isValid() ) // default value
+       c = QApplication::palette().color( QPalette::HighlightedText );
+      val = c; 
+      break;
+    case CheckStateRole:
+      // data object checked state for the specified column
+      // NOTE! three-state check is not supported currently
+      if ( obj->isCheckable( index.column() ) )
+       val = obj->isOn( index.column() ) ? Qt::Checked : Qt::Unchecked; 
+      break;
+    case SizeHintRole:
+      // data size hint
+      // NOTE! not supported currently
+      break;
+    default:
+      break;
+    } // ... switch ( role ) ...
+  } // ... if ( obj ) ...
+  return val;
+}
+
+/*!
+  \brief Set data for the specified model index and data role.
+  \param index model index
+  \param value new data value
+  \param role data role
+  \return \c true if data is set
+  \sa data()
+*/
+bool SUIT_TreeModel::setData( const QModelIndex& index, 
+                             const QVariant& value, int role )
+{
+  if ( index.isValid() && value.isValid() ) {
+    SUIT_DataObject* obj = object( index );
+    if ( obj ) {
+      // NOTE! only 'check state' data is supported by default
+      switch ( role ) {
+      case CheckStateRole:
+       // checked state
+       if ( obj->isCheckable( index.column() ) ) {
+         obj->setOn( value.toBool(), index.column() );
+         emit( dataChanged( index, index ) );
+         return true;
+       }
+       break;
+      default:
+       break;
+      }
+    }
+  }
+  return QAbstractItemModel::setData( index, value, role );
+}
+
+/*!
+  \brief Get data flags for specified model index.
+  \param index model index
+  \return data flags
+*/
+Qt::ItemFlags SUIT_TreeModel::flags( const QModelIndex& index ) const
+{
+  if ( !index.isValid() )
+    return 0;
+
+  SUIT_DataObject* obj = object( index );
+  Qt::ItemFlags f = 0;
+
+  if ( obj ) {
+    // data object is enabled
+    if ( obj->isEnabled() )
+      f = f | Qt::ItemIsEnabled;
+
+    // data object is selectable
+    if ( obj->isSelectable() )
+      f = f | Qt::ItemIsSelectable;
+
+    // data object is checkable
+    if ( obj->isCheckable( index.column() ) )
+      f = f | Qt::ItemIsUserCheckable;
+  }
+  return f;
+}
+
+/*!
+  \brief Get header data (can be used in any data view).
+  \param column column number
+  \param orientation header orientation
+  \param role data role
+  \return header data
+*/
+QVariant SUIT_TreeModel::headerData( int column, Qt::Orientation orientation,
+                                    int role ) const
+{
+  QVariant d;
+  // NOTE! only horizontal header is supported
+  if ( root() && orientation == Qt::Horizontal ) {
+    switch ( role ) {
+    case DisplayRole:
+      // column title
+      d = root()->columnTitle( column );
+      break;
+    case DecorationRole:
+      // column icon
+      d = root()->columnIcon( column );
+      break;
+    case AppropriateRole:
+      // appropriate flag (can column be hidden via context popup menu)
+      d = root()->appropriate( column );
+      break;
+    default:
+      break;
+    }
+  }
+  return d;
+}
+
+/*!
+  \brief Create model index.
+  \param row data row
+  \param column data column
+  \param parent parent model index
+  \return model index
+*/
+QModelIndex SUIT_TreeModel::index( int row, int column, 
+                                  const QModelIndex& parent ) const
+{
+  if ( hasIndex( row, column, parent ) ) {
+    TreeItem* parentItem = treeItem( parent );
+    if ( parentItem ) {
+      TreeItem* childItem = parentItem->child( row );
+      if ( childItem )
+       return createIndex( row, column, childItem );
+    }
+  }
+  return QModelIndex();
+}
+
+/*!
+  \brief Get parent model index.
+  \param index model index
+  \return parent model index
+*/
+QModelIndex SUIT_TreeModel::parent( const QModelIndex& index ) const
+{
+  if ( !index.isValid() )
+    return QModelIndex();
+
+  TreeItem* childItem = treeItem( index );
+  TreeItem* parentItem = childItem ? childItem->parent() : 0;
+
+  if ( !parentItem || parentItem == rootItem() )
+    return QModelIndex();
+
+  return createIndex( parentItem->position(), 0, parentItem );
+}
+
+/*!
+  \brief Get number of data columns.
+  \param parent parent model index (not used)
+  \return data columns number
+  \sa rowCount()
+*/
+int SUIT_TreeModel::columnCount( const QModelIndex& /*parent*/ ) const
+{
+  return root() ? root()->columnCount() : 0;
+}
+
+/*!
+  \brief Get number of data rows (children of the specified model index).
+  \param parent parent model index
+  \return data rows (children) number
+  \sa columnCount()
+*/
+int SUIT_TreeModel::rowCount( const QModelIndex& parent ) const
+{
+  if ( parent.column() > 0 )
+    return 0;
+
+  TreeItem* parentItem = treeItem( parent );
+
+  return parentItem ? parentItem->childCount() : 0;
+}
+
+/*!
+  \brief Get data object by the specified model index.
+  \param index model index
+  \return data object corresponding to the model index
+*/
+SUIT_DataObject* SUIT_TreeModel::object( const QModelIndex& index ) const
+{
+  return object( treeItem( index ) );
+}
+
+/*!
+  \brief Get model index by the specified data object.
+  \param obj data object
+  \param column data object column
+  \return model index
+*/
+QModelIndex SUIT_TreeModel::index( const SUIT_DataObject* obj, int column ) const
+{
+  if ( obj == root() )
+    return QModelIndex();
+
+  TreeItem* item = treeItem( obj );
+
+  return item ? createIndex( item->position(), column, item ) : QModelIndex();
+}
+
+/*!
+  \brief Get 'auto-delete data tree' flag value.
+  \return 'auto-delete data tree' flag value
+  \sa setAutoDeleteTree()
+*/
+bool SUIT_TreeModel::autoDeleteTree() const
+{
+  return myAutoDeleteTree;
+}
+
+/*!
+  \brief Set 'auto-delete data tree' flag value.
+
+  If this flag is set to \c true, the data tree is deleted when
+  the tree model is destroyed. Default value for this flag is \c false.
+
+  \param on 'auto-delete data tree' flag value
+  \sa autoDeleteTree()
+*/
+void SUIT_TreeModel::setAutoDeleteTree( const bool on )
+{
+  myAutoDeleteTree = on;
+}
+
+/*!
+  \brief Get 'auto-update tree' flag value.
+  \return 'auto-update tree' flag value
+  \sa setAutoUpdate(), updateTree()
+*/
+bool SUIT_TreeModel::autoUpdate() const
+{
+  return myAutoUpdate;
+}
+
+/*!
+  \brief Set 'auto-update tree' flag value.
+
+  If this flag is set to \c true (by default), the model is updated
+  automatically when data tree is changed.
+
+  \param on 'auto-update tree' flag value
+  \sa autoUpdate(), updateTree()
+*/
+void SUIT_TreeModel::setAutoUpdate( const bool on )
+{
+  if ( myAutoUpdate == on )
+    return;
+
+  SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
+                              this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
+  SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
+                              this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
+  myAutoUpdate = on;
+
+  if ( myAutoUpdate ) {
+    SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
+                             this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
+    SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
+                             this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
+
+    updateTree();
+  }
+}
+
+/*!
+  \brief Get tree updater.
+  \return current tree updater or 0 if it is not set
+*/
+SUIT_TreeUpdater* SUIT_TreeModel::updater() const
+{
+  return myUpdater;
+}
+
+/*!
+  \brief Set tree updater.
+  \param upd new tree updater
+*/
+void SUIT_TreeModel::setUpdater( SUIT_TreeUpdater* upd )
+{
+  if ( myUpdater )
+    delete myUpdater;
+
+  myUpdater = upd;
+
+  updateTree();
+}
+
+/*!
+  \brief Check if the specified column supports custom sorting.
+  \param column column index on which data is being sorted
+  \return \c true if column requires custom sorting
+  \sa lessThan()
+*/
+bool SUIT_TreeModel::customSorting( const int column ) const
+{
+  return root() ? root()->customSorting( column ) : false;
+}
+
+/*!
+  \brief Compares two model indexes for the sorting purposes.
+
+  This method is called only for those columns for which customSorting()
+  method returns \c true.
+
+  \param left first index to compare
+  \param right second index to compare
+  \return result of the comparison
+  \sa customSorting()
+*/
+bool SUIT_TreeModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
+{
+  QVariant ldata = data( left );
+  QVariant rdata = data( right );
+  return root() ? root()->compare( ldata, rdata, left.column() ) : false;
+}
+
+/*!
+  \brief Get item delegate for the model.
+  \return new item delegate
+*/
+QAbstractItemDelegate* SUIT_TreeModel::delegate() const
+{
+  return new SUIT_ItemDelegate( const_cast<SUIT_TreeModel*>( this ) );
+}
+
+/*!
+  \brief Update tree model.
+
+  Call this method when data tree is changed outside the model.
+  If the 'auto-update' flag is set to \c true, the model
+  is updated automatically when the data tree is changed.
+
+  \param index starting index for the updating
+  \sa setAutoUpdate()
+*/
+void SUIT_TreeModel::updateTree( const QModelIndex& index )
+{
+  updateTree( object( index ) );
+}
+
+/*!
+  \brief Update tree model.
+
+  Call this method when data tree is changed outside the model.
+  If the 'auto-update' flag is set to \c true, the model
+  is updated automatically when the data tree is changed.
+
+  \param obj starting data object for the updating
+  \sa setAutoUpdate()
+*/
+void SUIT_TreeModel::updateTree( SUIT_DataObject* obj )
+{
+  if ( !obj )
+    obj = root();
+
+  else if ( obj->root() != root() )
+    return;
+
+  synchronize<ObjPtr,ItemPtr,SUIT_TreeModel::TreeSync>( obj, 
+                                                       treeItem( obj ), 
+                                                       SUIT_TreeModel::TreeSync( this ) );
+}
+
+/*!
+  \brief Initialize tree model.
+*/
+void SUIT_TreeModel::initialize()
+{
+  SUIT_DataObject::disconnect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
+                              this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
+  SUIT_DataObject::disconnect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
+                              this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
+  if ( autoUpdate() ) {
+    SUIT_DataObject::connect( SIGNAL( inserted( SUIT_DataObject*, SUIT_DataObject* ) ),
+                             this, SLOT( onInserted( SUIT_DataObject*, SUIT_DataObject* ) ) );
+    SUIT_DataObject::connect( SIGNAL( removed( SUIT_DataObject*, SUIT_DataObject* ) ),
+                             this, SLOT( onRemoved( SUIT_DataObject*, SUIT_DataObject* ) ) );
+  }
+
+  myItems.clear(); // ????? is it really necessary
+
+  if ( !myRootItem )
+    myRootItem = new TreeItem( 0 );
+
+  updateTree();
+}
+
+/*!
+  \brief Get root tree item.
+  \return root tree item
+*/
+SUIT_TreeModel::TreeItem* SUIT_TreeModel::rootItem() const
+{
+  return myRootItem;
+}
+
+/*!
+  \brief Get tree item corresponding to the specified model index.
+  \param index model index
+  \return tree item or root item if index is invalid
+*/
+SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const QModelIndex& index ) const
+{
+  return index.isValid() ? static_cast<TreeItem*>( index.internalPointer() ) : rootItem();
+}
+
+/*!
+  \brief Get tree item corresponding to the specified data object.
+  \param obj data object
+  \return tree item or 0 if there is no tree item corresponding to \a obj
+*/
+SUIT_TreeModel::TreeItem* SUIT_TreeModel::treeItem( const SUIT_DataObject* obj ) const
+{
+  TreeItem* item = 0;
+
+  if ( obj == root() )
+    item = rootItem();
+  else if ( myItems.contains( const_cast<SUIT_DataObject*>( obj ) ) )
+    item = myItems[ const_cast<SUIT_DataObject*>( obj ) ];
+
+  return item;
+}
+
+/*!
+  \brief Get data object corresponding to the specified tree item.
+  \param item tree item
+  \return data object or 0 if there is no data object corresponding to \a item
+*/
+SUIT_DataObject* SUIT_TreeModel::object( const SUIT_TreeModel::TreeItem* item ) const
+{
+  if ( item == rootItem() )
+    return root();
+  SUIT_DataObject* obj = item ? item->dataObject() : 0;
+  return myItems.contains( obj ) ? obj : 0;
+}
+
+/*!
+  \brief Create an item corresponding to the data object.
+  \param obj source data object
+  \param parent parent tree item
+  \param after tree item after which new item should be inserted
+  \return created tree item or 0 if item could not be created
+*/
+SUIT_TreeModel::TreeItem* SUIT_TreeModel::createItem( SUIT_DataObject* obj,
+                                                     SUIT_TreeModel::TreeItem* parent, 
+                                                     SUIT_TreeModel::TreeItem* after )
+{
+  if ( !obj )
+    return 0;
+
+  SUIT_DataObject* parentObj = object( parent );
+  QModelIndex parentIdx = index( parentObj );
+
+  SUIT_DataObject* afterObj = after ? object( after ) : 0;
+  int row = afterObj ? afterObj->position() + 1 : 0;
+
+  beginInsertRows( parentIdx, row, row );
+
+  myItems[ obj ] = new TreeItem( obj, parent, after );
+
+  endInsertRows();
+
+  return myItems[ obj ];
+}
+
+/*!
+  \brief Update tree item.
+  \param item tree item to be updated
+*/
+void SUIT_TreeModel::updateItem( SUIT_TreeModel::TreeItem* item )
+{
+  if ( !item )
+    return;
+  
+  SUIT_DataObject* obj = object( item );
+  if ( !obj )
+    return;
+  
+  // update all columns corresponding to the given data object
+  QModelIndex firstIdx = index( obj, 0 );
+  QModelIndex lastIdx  = index( obj, obj->columnCount() - 1 );
+  emit dataChanged( firstIdx, lastIdx );
+}
+
+/*!
+  \brief Remove tree item (recursively).
+  \param item tree item to be removed
+*/
+void SUIT_TreeModel::removeItem( SUIT_TreeModel::TreeItem* item )
+{
+  if ( !item )
+    return;
+
+  // Remove list view items from <myItems> recursively for all children.
+  // Otherwise, "delete item" line below will destroy all item's children,
+  // and <myItems> will contain invalid pointers
+  while( item->childCount() )
+    removeItem( item->child( 0 ) );
+
+  SUIT_DataObject* obj = object( item );
+  
+  // Warning! obj can be deleted at this point!
+
+  SUIT_DataObject* parentObj = object( item->parent() );
+  QModelIndex parentIdx = index( parentObj, 0 );
+  int row = item->position();
+  
+  beginRemoveRows( parentIdx, row, row );
+  
+  myItems.remove( obj );
+
+  endRemoveRows();
+
+  if ( obj == root() )
+    setRoot( 0 );
+  else if ( item->parent() )
+    item->parent()->removeChild( item );
+
+  delete item;
+}
+
+/*!
+  \brief Called when the data object is inserted to the tree.
+  \param object data object being inserted
+  \param parent parent data object
+*/
+void SUIT_TreeModel::onInserted( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
+{
+  if ( autoUpdate() )
+    updateTree( parent );
+}
+
+/*!
+  \brief Called when the data object is removed from the tree.
+  \param object data object being removed
+  \param parent parent data object
+*/
+void SUIT_TreeModel::onRemoved( SUIT_DataObject* /*object*/, SUIT_DataObject* parent )
+{
+  if ( autoUpdate() )
+    updateTree( parent );
+}
+
+/*!
+  \class SUIT_ProxyModel
+  \brief Proxy model which can be used above the SUIT_TreeMovel class
+  to enable custom sorting/filtering of the data.
+
+  The SUIT_TreeModel class does not support custom sorting/filtering of the data.
+  To use these features, the SUIT_ProxyModel class can be used as top-level
+  wrapper for the SUIT_DataObject-based data tree model.
+*/
+
+/*!
+  \brief Constructor.
+  \param parent parent object
+*/
+SUIT_ProxyModel::SUIT_ProxyModel( QObject* parent )
+: QSortFilterProxyModel( parent ),
+  mySortingEnabled( true )
+{
+  setSourceModel( new SUIT_TreeModel( this ) );
+}
+
+/*!
+  \brief Constructor.
+  \param root root data object
+  \param parent parent object
+*/
+SUIT_ProxyModel::SUIT_ProxyModel( SUIT_DataObject* root, QObject* parent )
+: QSortFilterProxyModel( parent ),
+  mySortingEnabled( true )
+{
+  setSourceModel( new SUIT_TreeModel( root, this ) );
+}
+
+/*!
+  \brief Constructor.
+  \param model tree model
+  \param parent parent object
+*/
+SUIT_ProxyModel::SUIT_ProxyModel( SUIT_TreeModel* model, QObject* parent )
+: QSortFilterProxyModel( parent ),
+  mySortingEnabled( true )
+{
+  setSourceModel( model );
+}
+
+/*!
+  \brief Destructor.
+*/
+SUIT_ProxyModel::~SUIT_ProxyModel()
+{
+}
+
+/*!
+  \brief Get data tree root object.
+  \return data tree root
+  \sa setRoot()
+*/
+SUIT_DataObject* SUIT_ProxyModel::root() const
+{
+  return treeModel() ? treeModel()->root() : 0;
+}
+
+/*!
+  \brief Set data tree root object.
+  \param r new data tree root
+  \sa root()
+*/
+void SUIT_ProxyModel::setRoot( SUIT_DataObject* r )
+{
+  if ( treeModel() )
+    treeModel()->setRoot( r );
+}
+
+/*!
+  \brief Get data object by the specified model index.
+  \param index model index
+  \return data object corresponding to the model index
+*/
+SUIT_DataObject* SUIT_ProxyModel::object( const QModelIndex& index ) const
+{
+  return treeModel() ? treeModel()->object( mapToSource( index ) ) : 0;
+}
+
+/*!
+  \brief Get model index by the specified data object.
+  \param obj data object
+  \param column data object column
+  \return model index
+*/
+QModelIndex SUIT_ProxyModel::index( const SUIT_DataObject* obj, int column ) const
+{
+  return treeModel() ? mapFromSource( treeModel()->index( obj, column ) ) : QModelIndex();
+}
+
+/*!
+  \brief Get 'auto-delete data tree' flag value.
+  \return 'auto-delete data tree' flag value
+  \sa setAutoDeleteTree()
+*/
+bool SUIT_ProxyModel::autoDeleteTree() const
+{
+  return treeModel() ? treeModel()->autoDeleteTree() : false;
+}
+
+/*!
+  \brief Set 'auto-delete data tree' flag value.
+
+  If this flag is set to \c true, the data tree is deleted when
+  the tree model is destroyed. Default value for this flag is \c false.
+
+  \param on 'auto-delete data tree' flag value
+  \sa autoDeleteTree()
+*/
+void SUIT_ProxyModel::setAutoDeleteTree( const bool on )
+{
+  if ( treeModel() )
+    treeModel()->setAutoDeleteTree( on );
+}
+
+/*!
+  \brief Get 'auto-update tree' flag value.
+  \return 'auto-update tree' flag value
+  \sa setAutoUpdate(), updateTree()
+*/
+bool SUIT_ProxyModel::autoUpdate() const
+{
+  return treeModel() ? treeModel()->autoUpdate() : false;
+}
+
+/*!
+  \brief Set 'auto-update tree' flag value.
+
+  If this flag is set to \c true (by default), the model is updated
+  automatically when data tree is changed.
+
+  \param on 'auto-update tree' flag value
+  \sa autoUpdate(), updateTree()
+*/
+void SUIT_ProxyModel::setAutoUpdate( const bool on )
+{
+  if ( treeModel() )
+    treeModel()->setAutoUpdate( on );
+}
+
+/*!
+  \brief Get tree updater.
+  \return current tree updater or 0 if it is not set
+*/
+SUIT_TreeUpdater* SUIT_ProxyModel::updater() const
+{
+  return treeModel() ? treeModel()->updater() : 0;
+}
+
+/*!
+  \brief Set tree updater.
+  \param upd new tree updater
+*/
+void SUIT_ProxyModel::setUpdater( SUIT_TreeUpdater* upd )
+{
+  if ( treeModel() )
+    treeModel()->setUpdater( upd );
+}
+
+/*!
+  \brief Check if sorting is enabled.
+  \return \c true if sorting is enabled
+  \sa setSortingEnabled()
+*/
+bool SUIT_ProxyModel::isSortingEnabled() const
+{
+  return mySortingEnabled;
+}
+
+/*!
+  \brief Get item delegate for the model.
+  \return new item delegate
+*/
+QAbstractItemDelegate* SUIT_ProxyModel::delegate() const
+{
+  return treeModel() ? treeModel()->delegate() : 0;
+}
+
+/*!
+  \brief Update tree model.
+
+  Call this method when data tree is changed outside the model.
+  If the 'auto-update' flag is set to \c true, the model
+  is updated automatically when the data tree is changed.
+
+  \param index starting index for the updating
+  \sa setAutoUpdate()
+*/
+void SUIT_ProxyModel::updateTree( const QModelIndex& index )
+{
+  if ( treeModel() )
+    treeModel()->updateTree( mapToSource( index ) );
+}
+
+/*!
+  \brief Update tree model.
+
+  Call this method when data tree is changed outside the model.
+  If the 'auto-update' flag is set to \c true, the model
+  is updated automatically when the data tree is changed.
+
+  \param obj starting data object for the updating
+  \sa setAutoUpdate()
+*/
+void SUIT_ProxyModel::updateTree( SUIT_DataObject* obj )
+{
+  if ( treeModel() )
+    treeModel()->updateTree( obj );
+}
+
+/*!
+  \brief Compares two model indexes for the sorting purposes.
+  \param left first index to compare
+  \param right second index to compare
+  \return result of the comparison
+*/
+bool SUIT_ProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
+{
+  if ( !isSortingEnabled() && left.isValid() && right.isValid() ) {
+    return left.row() < right.row();
+  }
+  if ( treeModel() && treeModel()->customSorting( left.column() ) ) {
+    return treeModel()->lessThan( left, right );
+  }
+  return QSortFilterProxyModel::lessThan( left, right );
+}
+
+/*!
+  \brief Enable/disable sorting.
+  \param enabled new flag state
+  \sa isSortingEnabled()
+*/
+void SUIT_ProxyModel::setSortingEnabled( bool enabled )
+{
+  mySortingEnabled = enabled;
+  clear();
+}
+
+/*
+  \brief Get tree model.
+  \return tree model
+*/
+SUIT_TreeModel* SUIT_ProxyModel::treeModel() const
+{
+  return dynamic_cast<SUIT_TreeModel*>( sourceModel() );
+}
+
+/*!
+  \class SUIT_ItemDelegate
+  \brief An SUIT_DataObject-based item delegate class.
+
+  This class can be used to render the SUIT_DataObject-based item
+  in the widgets like QTreeView and others.
+  Refer to the Qt 4 documentation, model/view architecture 
+  section for more details).
+*/
+
+/*!
+  \brief Constructor.
+  \param parent parent object
+*/
+SUIT_ItemDelegate::SUIT_ItemDelegate( QObject* parent )
+: QItemDelegate( parent )
+{
+}
+
+/*!
+  \brief Render the item in the widget.
+
+  Customizes the item colors for the specific roles.
+
+  \param painter painter
+  \param option painting option
+  \param index model index being rendered
+*/
+void SUIT_ItemDelegate::paint( QPainter* painter, 
+                              const QStyleOptionViewItem& option,
+                              const QModelIndex& index ) const
+{
+  QStyleOptionViewItem opt = option;
+  if ( index.isValid() ) {
+    // Note: we check into account only custom roles; other roles are process
+    //       correctly by the QItemDelegate class
+    QVariant val = index.data( SUIT_TreeModel::BaseColorRole );
+    if ( val.isValid() && val.value<QColor>().isValid() )
+      opt.palette.setBrush( QPalette::Base, val.value<QColor>() );
+    val = index.data( SUIT_TreeModel::TextColorRole );
+    if ( val.isValid() && val.value<QColor>().isValid() )
+      opt.palette.setBrush( QPalette::Text, val.value<QColor>() );
+    val = index.data( SUIT_TreeModel::HighlightRole );
+    if ( val.isValid() && val.value<QColor>().isValid() )
+      opt.palette.setBrush( QPalette::Highlight, val.value<QColor>() );
+    val = index.data( SUIT_TreeModel::HighlightedTextRole );
+    if ( val.isValid() && val.value<QColor>().isValid() )
+      opt.palette.setBrush( QPalette::HighlightedText, val.value<QColor>() );
+  }
+  QItemDelegate::paint( painter, opt, index );
+}
diff --git a/src/SUIT/SUIT_TreeModel.h b/src/SUIT/SUIT_TreeModel.h
new file mode 100755 (executable)
index 0000000..c0e40c5
--- /dev/null
@@ -0,0 +1,212 @@
+// 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
+//
+// File:   SUIT_TreeModel.h
+// Author: Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+//
+
+#ifndef SUIT_TREEMODEL_H
+#define SUIT_TREEMODEL_H
+
+#include "SUIT.h"
+
+#include <Qtx.h>
+
+#include <QAbstractItemModel>
+#include <QSortFilterProxyModel>
+#include <QModelIndex>
+#include <QItemDelegate>
+#include <QVariant>
+
+#ifdef WIN32
+#pragma warning( disable:4251 )
+#endif
+
+class SUIT_DataObject;
+class SUIT_TreeModel;
+
+class SUIT_EXPORT SUIT_TreeUpdater 
+{
+public:
+  SUIT_TreeUpdater( SUIT_TreeModel* ) {};
+  virtual ~SUIT_TreeUpdater() {};
+  virtual void update( SUIT_DataObject* theObj ) = 0;
+};
+
+class SUIT_EXPORT SUIT_TreeModel : public QAbstractItemModel
+{
+  Q_OBJECT
+
+private:
+  class TreeItem;
+  class TreeSync;
+  typedef SUIT_DataObject*          ObjPtr;
+  typedef SUIT_TreeModel::TreeItem* ItemPtr;
+public:
+  //! Data role
+  typedef enum {
+    DisplayRole         = Qt::DisplayRole,       //!< text label
+    DecorationRole      = Qt::DecorationRole,    //!< icon
+    EditRole            = Qt::EditRole,          //!< edit mode
+    ToolTipRole         = Qt::ToolTipRole,       //!< tooltip
+    StatusTipRole       = Qt::StatusTipRole,     //!< status tip
+    WhatsThisRole       = Qt::WhatsThisRole,     //!< what's this info
+    FontRole            = Qt::FontRole,          //!< font
+    TextAlignmentRole   = Qt::TextAlignmentRole, //!< text alignment
+    BackgroundRole      = Qt::BackgroundRole,    //!< background color
+    ForegroundRole      = Qt::ForegroundRole,    //!< text color
+    CheckStateRole      = Qt::CheckStateRole,    //!< check state
+    SizeHintRole        = Qt::SizeHintRole,      //!< size hint
+    BaseColorRole       = Qt::UserRole,          //!< (editor) background color
+    TextColorRole,                               //!< (editor) text color    (Qt::UserRole + 1)
+    HighlightRole,                               //!< highlight color        (Qt::UserRole + 2)
+    HighlightedTextRole,                         //!< highlighted text color (Qt::UserRole + 3)
+    AppropriateRole     = Qtx::AppropriateRole   //!< appropriate flag       (Qt::UserRole + 100)
+  } Role;
+
+  SUIT_TreeModel( QObject* = 0 );
+  SUIT_TreeModel( SUIT_DataObject*, QObject* = 0 );
+  ~SUIT_TreeModel();
+
+  SUIT_DataObject*       root() const;
+  void                   setRoot( SUIT_DataObject* );
+
+  virtual QVariant       data( const QModelIndex&, int = DisplayRole ) const;
+  virtual bool           setData( const QModelIndex&, const QVariant&, int = EditRole );
+  virtual Qt::ItemFlags  flags( const QModelIndex& ) const;
+  virtual QVariant       headerData( int, Qt::Orientation, int = Qt::DisplayRole ) const;
+
+  virtual QModelIndex    index( int, int, const QModelIndex& = QModelIndex() ) const;
+  virtual QModelIndex    parent( const QModelIndex& ) const;
+
+  virtual int            columnCount( const QModelIndex& = QModelIndex() ) const;
+  virtual int            rowCount( const QModelIndex& = QModelIndex() ) const;
+
+  SUIT_DataObject*       object( const QModelIndex& = QModelIndex() ) const;
+  QModelIndex            index( const SUIT_DataObject*, int = 0 ) const;
+
+  bool                   autoDeleteTree() const;
+  void                   setAutoDeleteTree( const bool );
+
+  bool                   autoUpdate() const;
+  void                   setAutoUpdate( const bool );
+
+  SUIT_TreeUpdater*      updater() const;
+  void                   setUpdater( SUIT_TreeUpdater* );
+
+  virtual bool           customSorting( const int ) const;
+  virtual bool           lessThan( const QModelIndex& left, const QModelIndex& right ) const;
+
+  QAbstractItemDelegate* delegate() const;
+
+public slots:
+  virtual void           updateTree( const QModelIndex& );
+  virtual void           updateTree( SUIT_DataObject* = 0 );
+
+private:
+  void                   initialize();
+
+  TreeItem*              rootItem() const;
+  TreeItem*              treeItem( const QModelIndex& ) const;
+  TreeItem*              treeItem( const SUIT_DataObject* ) const;
+  SUIT_DataObject*       object( const TreeItem* ) const;
+
+  TreeItem*              createItem( SUIT_DataObject*,
+                                    TreeItem* = 0, 
+                                    TreeItem* = 0 );
+  void                   updateItem( TreeItem* );
+  void                   removeItem( TreeItem* );
+
+private slots:
+  void                   onInserted( SUIT_DataObject*, SUIT_DataObject* );
+  void                   onRemoved( SUIT_DataObject*, SUIT_DataObject* );
+
+private:
+  typedef QMap<SUIT_DataObject*, TreeItem*> ItemMap;
+  
+  SUIT_DataObject*       myRoot;
+  TreeItem*              myRootItem;
+  ItemMap                myItems;
+  bool                   myAutoDeleteTree;
+  bool                   myAutoUpdate;
+  SUIT_TreeUpdater*      myUpdater;
+
+  friend class SUIT_TreeModel::TreeSync;
+};
+
+class SUIT_EXPORT SUIT_ProxyModel : public QSortFilterProxyModel
+{
+  Q_OBJECT
+
+public:
+  SUIT_ProxyModel( QObject* = 0 );
+  SUIT_ProxyModel( SUIT_DataObject*, QObject* = 0 );
+  SUIT_ProxyModel( SUIT_TreeModel*, QObject* = 0 );
+  ~SUIT_ProxyModel();
+
+  SUIT_DataObject*       root() const;
+  void                   setRoot( SUIT_DataObject* );
+
+  SUIT_DataObject*       object( const QModelIndex& = QModelIndex() ) const;
+  QModelIndex            index( const SUIT_DataObject*, int = 0 ) const;
+
+  bool                   autoDeleteTree() const;
+  void                   setAutoDeleteTree( const bool );
+
+  bool                   autoUpdate() const;
+  void                   setAutoUpdate( const bool );
+
+  SUIT_TreeUpdater*      updater() const;
+  void                   setUpdater( SUIT_TreeUpdater* );
+  
+  bool                   isSortingEnabled() const;
+
+  QAbstractItemDelegate* delegate() const;
+
+public slots:
+  virtual void           updateTree( const QModelIndex& );
+  virtual void           updateTree( SUIT_DataObject* = 0 );
+  void                   setSortingEnabled( bool );
+
+protected:
+  virtual bool           lessThan( const QModelIndex&, const QModelIndex& ) const;
+
+private:
+  SUIT_TreeModel*        treeModel() const;
+
+private:
+  bool                   mySortingEnabled;
+};
+
+class SUIT_EXPORT SUIT_ItemDelegate : public QItemDelegate
+{
+  Q_OBJECT
+
+public:
+  SUIT_ItemDelegate( QObject* = 0 );
+  
+  virtual void paint( QPainter*, const QStyleOptionViewItem&,
+                     const QModelIndex& ) const;
+};
+
+#ifdef WIN32
+#pragma warning( default:4251 )
+#endif
+
+#endif // SUIT_TREEMODEL_H
index 929255b36fe63999846283b28e2feb3cb8aa1a71..ccceeaa0cafe2daa2a8a53e5ada6d575a1e10629 100644 (file)
 //
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
+// File   : SUIT_TreeSync.h
+// Author : Alexander SOLOVYOV
+//
 
-#ifndef SUIT_TREE_SYNC_HEADER
-#define SUIT_TREE_SYNC_HEADER
+#ifndef SUIT_TREESYNC_H
+#define SUIT_TREESYNC_H
 
 #include <QList>
 
 /*!
-  \struct DiffItem
-  \brief Struct representing difference between items
+  \brief The structure representing difference between source and destination items.
+
+  The different combinations of source and target items values imply the different actions 
+  to be performed in the target data tree:
+  - source item is null, target item is not null : the item should be removed from the target tree
+  - source item is not null, target item is null : new item should be added to the target tree
+  - both source and target items are not null : the target item can be updated if necessary
+  - both source and target items are null : error   
 */
 template <class SrcItem, class TrgItem>
 struct DiffItem
 {
-  SrcItem  mySrc;
-  /*! 
-    \var mySrc
-    if it is null, then this item is to deleted
-  */
-  TrgItem  myTrg;
-  /*!
-    \var myTrg
-    if it is null, then this item is to added
-    if both fields aren't null, then this item is to update
-  */
+  SrcItem  mySrc;      //!< source tree item
+  TrgItem  myTrg;      //!< target tree item
 };
 
-/*!
-  \brief synchronizes two trees
-*/
+
+//
+// Function prototypes.
+//
+
 template <class SrcItem, class TrgItem, class TreeData>
 TrgItem synchronize( const SrcItem&, const TrgItem&, const TreeData& );
 
-/*!
-  \brief compares children 
-*/
 template <class SrcItem, class TrgItem, class TreeData>
-void diffSiblings( const SrcItem&, const TrgItem&,
-                   QList < DiffItem < SrcItem,TrgItem > >&,
-                   const TreeData& );
+QList< DiffItem<SrcItem,TrgItem> > diffSiblings( const SrcItem&, 
+                                                const TrgItem&, 
+                                                const TreeData& );
 
-/*!
-  \brief create item with children (subtree)
-*/
 template <class SrcItem, class TrgItem, class TreeData>
-TrgItem createSubTree( const SrcItem&, const TrgItem&, const TrgItem&, const bool, const TreeData& );
+TrgItem createSubTree( const SrcItem&, const TrgItem&, const TrgItem&, const TreeData& );
 
-/*!
-  \brief find equal element in list
-*/
 template <class SrcItem, class TrgItem, class TreeData>
-const typename QList<TrgItem>::const_iterator findEqual( const QList<TrgItem>& l,
+const typename QList<TrgItem>::const_iterator findEqual( const SrcItem& it,
                                                         const typename QList<TrgItem>::const_iterator& first,
-                                                        const SrcItem& it,
+                                                        const typename QList<TrgItem>::const_iterator& last,
                                                         const TreeData& td );
 
 
-
+//
+// Function imlpementation.
+//
 
 /*!
-  Synchronizes two trees by comparing corresponding items
-  \param r1 - start item from first tree
-  \param r2 - start item from second tree
-  \param td - auxiliary class providing following methods:
-  <ul>
-  <li> bool     isEqual( const SrcItem&, const TrgItem& ) const - returns true if items are equal
-  <li> SrcItem  nullSrc() const - returns null SrcItem
-  <li> TrgItem  nullTrg() const - returns null TrgItem
-  <li> TrgItem  createItem( 
-    <ol>
-      <li> const SrcItem& src,    - corresponding SrcItem
-      <li> const TrgItem& parent, - parent TrgItem
-      <li> const TrgItem& after,  - TrgItem after that new item must be added
-      <li> const bool prepend     - whether new item must be added as first 
-    </ol>
-    ) const - creates new TrgItem
-  <li> void     updateItem( const TrgItem& ) const - updates TrgItem without recreation
-  <li> void     deleteItemWithChildren( const TrgItem& ) const - deletes TrgItem with all children
-  <li> void     children( const SrcItem&, QList<SrcItem>& ) const - fills list with children
-  <li> void     children( const TrgItem&, QList<TrgItem>& ) const - fills list with children
-  <li> SrcItem  parent( const SrcItem& ) const - return parent SrcItem
-  <li> TrgItem  parent( const TrgItem& ) const - return parent SrcItem
-  </ul>
+  \brief Synchronize two data trees by recurive comparing of the corresponding items.
+
+  \param r1 starting item from the source  data tree
+  \param r2 starting item from the target data tree
+  \param td functor class
+  \return the target tree item (updated or just created) corresponding to the starting
+     data object
+
+  Actual comparing of the items and the syncronization of the trees is performed by the
+  functor class which is passed as the last parameter of the function.
+  The functor class should implement the following methods:
+  - \b bool \b isEqual( \b const \b SrcItem& \p src, \b const \b TrgItem& \p tgt ) \b const;
+    - \a src source tree item 
+    - \a tgt target tree item
+    - compares items and returns \c true if the items are equal (correspond to each other)
+  - \b SrcItem \b nullSrc() \b const;
+    - returns null source tree itemm
+  - \b TrgItem \b nullTrg() \b const
+    - returns null target tree item
+  - \b TrgItem \b createItem( \b const \b SrcItem& \p src, \b const \b TrgItem& \p parent, \b const \b TrgItem& \p after ) \b const;
+    - \a src source item
+    - \a parent parent target item
+    - \a after target tree item after which new item shoud be inserted (if null, the item is added to the end)
+    - creates new ite in the target tree which correspond to the source item and returns created item
+  - \b void \b updateItem( \b const \b SrcItem& \p src, \b const \b TrgItem& \p tgt ) \b const;
+    - \a src source tree item 
+    - \a tgt the item in the target tree to be updated
+    - updates target treeitem
+  - \b void \b deleteItemWithChildren( \b const \b TrgItem& \p tgt ) \b const;
+    - \a tgt the item in the target tree to be removed
+    - deletes target tree item (recursively)
+  - \b QList<SrcItem> \b children( \b const \b SrcItem& \p parent ) \b const;
+    - \a parent the parent item in the source tree
+    - returns the child items list
+  - \b QList<TrgItem> \b children( \b const \b TrgItem& \p parent ) \b const;
+    - \a parent the parent item in the target tree
+    - returns the child items list
+  - \b TrgItem \b parent( \b const \b TrgItem& \p tgt ) \b const;
+    - \a tgt target tree item
+    - returns the item which is parent for the specified source tree item
 */
 template <class SrcItem, class TrgItem, class TreeData>
 TrgItem synchronize( const SrcItem& r1, const TrgItem& r2, const TreeData& td )
 {
-  if( td.isEqual( r1, r2 ) )
-  {
+  if ( td.isEqual( r1, r2 ) ) {
     // update items themselves
     td.updateItem( r1, r2 );
-
-    // iterate 'siblings' (direct children) 
-    QList< DiffItem< SrcItem, TrgItem > > d;
-    diffSiblings( r1, r2, d, td );
-
+    
+    // iterate through children
+    QList< DiffItem< SrcItem, TrgItem > > d =  diffSiblings( r1, r2, td );
+    
     typename QList< DiffItem< SrcItem, TrgItem > >::const_iterator anIt = d.begin(), aLast = d.end();
     TrgItem lastItem = td.nullTrg();
-    //    TrgItem tail = td.nullTrg();
-    for( ; anIt!=aLast; anIt++ )
-    {
+
+    for ( ; anIt != aLast; anIt++ ) {
       const DiffItem<SrcItem,TrgItem>& item = *anIt;
-      if( item.mySrc==td.nullSrc() )
-       if( item.myTrg==td.nullTrg() )
+      if ( item.mySrc == td.nullSrc() ) {
+       if ( item.myTrg == td.nullTrg() )
          qDebug( "error: both null" );
         else
-         //to delete
+         // delete item
          td.deleteItemWithChildren( item.myTrg );
+      }
       else {
-       if( item.myTrg==td.nullTrg() )
-       {
-         //to add
-         TrgItem nitem = createSubTree( item.mySrc, r2, lastItem, lastItem==td.nullTrg(), td );
-         if( nitem!=td.nullTrg() )
+       if ( item.myTrg == td.nullTrg() ) {
+         // add item (recursively)
+         TrgItem nitem = createSubTree( item.mySrc, r2, lastItem, td );
+         if ( nitem != td.nullTrg() )
            lastItem = nitem;
        }
-        else
-       {
-         //to update
-         td.updateItem( item.mySrc, item.myTrg );
+        else {
+         // update item
          synchronize( item.mySrc, item.myTrg, td );
          lastItem = item.myTrg;
        }
       }
     }
-
     return r2;
   }
-  else
-  {
-    TrgItem new_r2 = createSubTree( r1, td.parent( r2 ), r2, false, td );
-    if( r2!=td.nullTrg() )
+  else {
+    TrgItem new_r2 = td.nullTrg();
+    if ( r1 != td.nullSrc() ) {
+      // add new item (recursively)
+      new_r2 = createSubTree( r1, td.parent( r2 ), r2, td );
+    }
+    if ( r2 != td.nullTrg() ) {
+      // delete old one (if it is not null)
       td.deleteItemWithChildren( r2 );
+    }
     return new_r2;
   }
 }
 
 /*!
-  Finds equal element in list
-  \return iterator
-  \param l - list to search
-  \param first - start iterator 
-  \param it - item to be found
-  \param td - tree data object (provides auxiliary methods)
+  \brief Find the item in the target tree which correspond to the specified source tree item.
+  \param it source item for which correspondence is to be found
+  \param first iterator pointing to the item in the list \a l from which search shoud be started
+  \param last iterator pointing to the item in the list \a l the search to be finished at
+  \param td functor class
+  \return iterator pointing to the item in the list \l if the correspondence is found or iterator
+     \a last if the correspondence is not found
+  \sa synchronize()
 */
 template <class SrcItem, class TrgItem, class TreeData>
-const typename QList<TrgItem>::const_iterator findEqual( const QList<TrgItem>& l,
+const typename QList<TrgItem>::const_iterator findEqual( const SrcItem& it,
                                                         const typename QList<TrgItem>::const_iterator& first,
-                                                        const SrcItem& it,
+                                                        const typename QList<TrgItem>::const_iterator& last,
                                                         const TreeData& td )
 {
-  typename QList<TrgItem>::const_iterator cur = first, last = l.end();
-  for( ; cur!=last; cur++ )
-    if( td.isEqual( it, *cur ) )
+  typename QList<TrgItem>::const_iterator cur = first;
+  for ( ; cur != last; cur++ ) {
+    if ( td.isEqual( it, *cur ) )
       return cur;
+  }
   return last;
 }
 
 /*!
-  Compares children of objects src and trg
-  \param src - SrcItem to be checked
-  \param trg - TrgItem to be checked
-  \param d - map of difference to be filled
-  \param td - tree data object (provides auxiliary methods)
+  \brief Compare children of the source and target trees to find differences.
+  \param src parent source item
+  \param trg parent target item
+  \param td functor class
+  \return list of the differences
+  \sa synchronize()
 */
 template <class SrcItem, class TrgItem, class TreeData>
-void diffSiblings( const SrcItem& src, const TrgItem& trg,
-                  QList < DiffItem < SrcItem,TrgItem > >& d,
-                  const TreeData& td )
+QList< DiffItem<SrcItem,TrgItem> > diffSiblings( const SrcItem& src, const TrgItem& trg,
+                                                const TreeData& td )
 {
   //if( src==td.nullSrc() || trg==td.nullTrg() )
   //  return;
-
-  QList<SrcItem> src_ch;
-  QList<TrgItem> trg_ch;
-  td.children( src, src_ch );
-  td.children( trg, trg_ch );
+  
+  QList< DiffItem<SrcItem,TrgItem> > d;
+   
+  QList<SrcItem> src_ch = td.children( src );
+  QList<TrgItem> trg_ch = td.children( trg );
 
   typename QList<SrcItem>::const_iterator src_it = src_ch.begin(), src_last = src_ch.end();
-  typename QList<TrgItem>::const_iterator cur = trg_ch.begin(), trg_last = trg_ch.end();
+  typename QList<TrgItem>::const_iterator cur    = trg_ch.begin(), trg_last = trg_ch.end();
 
-  for( ; src_it!=src_last; src_it++ )
-  {
+  for ( ; src_it != src_last; src_it++ ) {
     typename QList<TrgItem>::const_iterator f =
-      findEqual<SrcItem, TrgItem, TreeData>( trg_ch, cur, *src_it, td );
-    if( f!=trg_last )  //is found
-    {
-      //mark all items before found as "to be deleted"
-      for( typename QList<TrgItem>::const_iterator it = cur; it!=f; it++ )
-      {
+      findEqual<SrcItem, TrgItem, TreeData>( *src_it, cur, trg_last, td );
+    if ( f != trg_last )  { 
+      // target is found
+      // mark all items before found one as "to be deleted"
+      for ( typename QList<TrgItem>::const_iterator it = cur; it != f; it++ ) {
        DiffItem<SrcItem,TrgItem> ndiff;
        ndiff.mySrc = td.nullSrc();
-       ndiff.myTrg = *it; //to delete;
+       ndiff.myTrg = *it;        // delete item
        d.append( ndiff );
       }
       cur = f;
       DiffItem<SrcItem,TrgItem> ndiff;
       ndiff.mySrc = *src_it;
-      ndiff.myTrg = *cur; //update this item
+      ndiff.myTrg = *cur;         // update this (found) item
       d.append( ndiff );
       cur++;
     }
-    else //not found
-    {
+    else {
+      // target is not found
       DiffItem<SrcItem,TrgItem> ndiff;
       ndiff.mySrc = *src_it;
-      ndiff.myTrg = td.nullTrg(); //add this item
+      ndiff.myTrg = td.nullTrg(); // add item
       d.append( ndiff );
     }
   }
-  for( ; cur!=trg_last; cur++ )
-  {
+  // delete rest items
+  for ( ; cur != trg_last; cur++ ) {
     DiffItem<SrcItem,TrgItem> ndiff;
     ndiff.mySrc = td.nullSrc();
-    ndiff.myTrg = *cur; //to delete;
+    ndiff.myTrg = *cur;           // delete item
     d.append( ndiff );
   }
+  
+  return d;
 }
 
 /*!
-  Creates sub-tree
-  \return root of just created sub-tree
-  \param src - corresponding SrcItem
-  \param parent - parent of new TrgItem
-  \param after - TrgItem, after that new item must be added
-  \param asFirst - true if TrgItem must be added as first
-  \param td - tree data object (provides auxiliary methods)
+  \brief Create an item with all its children recursively in the target tree.
+  \param src source tree item
+  \param parent parent item in the target tree
+  \param after item in the target tree after which new item shoud be inserted
+  \param td functor class
+  \return created item
+  \sa synchronize()
 */
 template <class SrcItem, class TrgItem, class TreeData>
 TrgItem createSubTree( const SrcItem& src, const TrgItem& parent,
-                      const TrgItem& after, const bool asFirst,
-                      const TreeData& td )
+                      const TrgItem& after, const TreeData& td )
 {
-  if( src==td.nullSrc() )
+  if ( src == td.nullSrc() )
     return td.nullTrg();
 
-  TrgItem nitem = td.createItem( src, parent, after, asFirst );
-  if( nitem==td.nullTrg() )
+  TrgItem nitem = td.createItem( src, parent, after );
+  if ( nitem == td.nullTrg() )
     return nitem;
 
-  QList<SrcItem> ch;
-  td.children( src, ch );
+  QList<SrcItem> ch = td.children( src );
   typename QList<SrcItem>::const_iterator anIt = ch.begin(), aLast = ch.end();
-  for( ; anIt!=aLast; anIt++ )
-    createSubTree( *anIt, nitem, td.nullTrg(), false, td );
+  TrgItem last = td.nullTrg();
+  for( ; anIt != aLast; anIt++ )
+    last = createSubTree( *anIt, nitem, last, td );
 
   return nitem;
 }
 
-#endif
+#endif // SUIT_TREESYNC_H
index 6b44e7f2434ba1db8ea23f8eea66a1cbc0e4a59b..26b3064f9e1b2af536519a0fdc421703992b5605 100644 (file)
@@ -99,6 +99,10 @@ Do you want to overwrite it?</translation>
         <source>MEN_DESK_WINDOW_TILE</source>
         <translation>&amp;Tile</translation>
     </message>
+    <message>
+        <source>NAME_COLUMN</source>
+        <translation>Name</translation>
+    </message>
 </context>
 <context>
     <name>SUIT_Study</name>