SUIT_Study.h \
SUIT_Tools.h \
SUIT_TreeSync.h \
+ SUIT_TreeModel.h \
SUIT_ViewManager.h \
SUIT_ViewModel.h \
SUIT_ViewWindow.h
SUIT_Session.cxx \
SUIT_Study.cxx \
SUIT_Tools.cxx \
+ SUIT_TreeModel.cxx \
SUIT_ViewManager.cxx \
SUIT_ViewModel.cxx \
SUIT_ViewWindow.cxx
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
//
// 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
#define SUIT_ASSERT(x)
#endif
-#endif
+#endif // SUIT_H
// 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;
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;
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;
}
/*!
- 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;
}
/*!
- 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;
}
/*!
- 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 )
}
/*!
- 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;
}
/*!
- 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 )
}
/*!
- 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 )
}
/*!
- 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
{
}
/*!
- 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 )
{
}
/*!
- 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
+*/
//
// 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
#include <QObject>
#include <QString>
#include <QPixmap>
+#include <QFont>
class SUIT_DataObject;
class SUIT_DataObjectKey;
#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();
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;
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
--- /dev/null
+// 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 );
+}
--- /dev/null
+// 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
//
// 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
<source>MEN_DESK_WINDOW_TILE</source>
<translation>&Tile</translation>
</message>
+ <message>
+ <source>NAME_COLUMN</source>
+ <translation>Name</translation>
+ </message>
</context>
<context>
<name>SUIT_Study</name>