1 // Copyright (C) 2007-2013 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // File : SUIT_DataObject.cxx
24 // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
28 #include "SUIT_DataObject.h"
29 #include "SUIT_DataObjectKey.h"
32 SUIT_DataObject::Signal* SUIT_DataObject::mySignal = 0;
35 \class SUIT_DataObject
36 \brief Data object representing the data instance in the tree-like hierarchy.
38 Data object represents uniform data tree structure recommended to use in the
39 SUIT-based applications.
45 Creates the data object with the specified parent.
46 To create the top-level object, pass 0 as parameter.
48 \param p parent object
50 SUIT_DataObject::SUIT_DataObject( SUIT_DataObject* p )
58 signal()->emitCreated( this );
64 Destroys all the children if "auto-delete children" flag is set.
66 SUIT_DataObject::~SUIT_DataObject()
68 SUIT_DataObject* p = myParent;
73 p->removeChild( this );
75 signal()->emitDestroyed( this );
77 for ( DataObjectList::iterator it = myChildren.begin(); it != myChildren.end(); ++it )
80 if ( autoDeleteChildren() )
82 for ( DataObjectList::iterator itr = myChildren.begin(); itr != myChildren.end(); ++itr )
88 \brief Get the root object.
89 \return root object of the data tree
91 SUIT_DataObject* SUIT_DataObject::root() const
93 return parent() ? parent()->root() : (SUIT_DataObject*)this;
97 \brief Get the first child object.
98 \return first child object or 0 if there are no children
101 SUIT_DataObject* SUIT_DataObject::firstChild() const
103 SUIT_DataObject* child = 0;
104 if ( !myChildren.isEmpty() )
105 child = myChildren.first();
110 \brief Get the last child object.
111 \return last child object or 0 if there are no children
114 SUIT_DataObject* SUIT_DataObject::lastChild() const
116 SUIT_DataObject* child = 0;
117 if ( !myChildren.isEmpty() )
118 child = myChildren.last();
123 \brief Get the number of the child objects.
124 \return number of the children
126 int SUIT_DataObject::childCount() const
128 return myChildren.count();
132 \brief Get the index of the specified object in the child list.
133 \param obj child object
134 \return subobject position or -1 if it does not belong to this object
136 int SUIT_DataObject::childPos( const SUIT_DataObject* obj ) const
138 return myChildren.indexOf( (SUIT_DataObject*)obj );
142 \brief Get child object by the specified index.
143 \param idx child object index
144 \return child object or 0 if index is out of range
146 SUIT_DataObject* SUIT_DataObject::childObject( const int idx ) const
148 SUIT_DataObject* child = 0;
150 if ( idx >= 0 && idx < myChildren.count() )
151 child = myChildren.at( idx );
157 \brief Get the object level in the tree structure.
159 Root object has level 0.
161 \return object level.
163 int SUIT_DataObject::level() const
166 SUIT_DataObject* p = parent();
175 \brief Get the position of the data object in its parent's children list
176 \return data object position
178 int SUIT_DataObject::position() const
180 return myParent ? myParent->childPos( this ) : 0;
184 \brief Get the next sibling data object in the children list.
185 \return child object or 0 if there is no next sibling
188 SUIT_DataObject* SUIT_DataObject::nextBrother() const
190 return myParent ? myParent->childObject( myParent->childPos( this ) + 1 ) : 0;
194 \brief Get the previous sibling data object in the children list.
195 \return child object or 0 if there is no previous sibling
198 SUIT_DataObject* SUIT_DataObject::prevBrother() const
200 return myParent ? myParent->childObject( myParent->childPos( this ) - 1 ) : 0;
204 \brief Get "auto-delete children" flag.
205 \return \c true if the object should delete all its children on destroying
206 \sa setAutoDeleteChildren()
208 bool SUIT_DataObject::autoDeleteChildren() const
214 \brief Set "auto-delete children" flag.
216 If this flag is on (default), the object will delete
217 all its children on destroying.
219 \param on new flag value
220 \sa autoDeleteChildren()
222 void SUIT_DataObject::setAutoDeleteChildren( const bool on )
228 \brief Get all children.
230 If parameter \a rec is \c true then function collects all
231 the children recursively.
233 \param lst returning list of children
234 \param rec if \c true collect all children recursively
236 void SUIT_DataObject::children( DataObjectList& lst, const bool rec ) const
238 for ( DataObjectList::const_iterator it = myChildren.begin(); it != myChildren.end(); ++it )
242 (*it)->children( lst, rec );
247 \brief Get all children.
250 If parameter \a rec is \c true then function collects all
251 the children recursively.
253 \param rec if \c true collect all children recursively
254 \return list of children
256 DataObjectList SUIT_DataObject::children( const bool rec )
259 children( lst, rec );
264 \brief Add new child object to the end of the children list.
265 \param obj child object being added
267 void SUIT_DataObject::appendChild( SUIT_DataObject* obj )
269 insertChild( obj, myChildren.count() );
273 \brief Insert new child object to the list of the children.
274 \param obj child object being added
275 \param position child position
277 void SUIT_DataObject::insertChild( SUIT_DataObject* obj, int position )
279 if ( !obj || myChildren.contains( obj ) )
282 int pos = position < 0 ? myChildren.count() : position;
283 myChildren.insert( qMin( pos, (int)myChildren.count() ), obj );
284 obj->setParent( this );
285 signal()->emitInserted( obj, this );
289 \brief Insert new child object into the list of the children (faster version of insertChild without signal).
290 \param obj child object being added
291 \param position child position
293 void SUIT_DataObject::insertChildAtPos( SUIT_DataObject* obj, int position )
296 int pos = position < 0 ? myChildren.count() : position;
297 myChildren.insert( qMin( pos, (int)myChildren.count() ), obj );
298 obj->assignParent( this );
302 \brief Remove the specified child object reference.
303 \param obj child object being removed
304 \param del if \c true, the child object is destroyed
306 void SUIT_DataObject::removeChild( SUIT_DataObject* obj, const bool del )
311 if ( myChildren.removeAll( obj ) ) {
312 signal()->emitRemoved( obj, this );
321 \brief Replace the specified child object by another object.
322 \param src child object being replaced
323 \param trg new child object
324 \param del if \c true, the previous object is destroyed
325 \return \c true if the object has been replaced
327 bool SUIT_DataObject::replaceChild( SUIT_DataObject* src, SUIT_DataObject* trg, const bool del )
332 int idx = childPos( trg );
335 int pos = childPos( src );
339 insertChild( trg, idx );
343 insertChild( trg, pos );
353 \brief Change the parent for all children from specified object to this one.
354 \param obj object which children to be reparented
356 void SUIT_DataObject::reparentChildren( const SUIT_DataObject* obj )
362 obj->children( lst );
363 for ( DataObjectList::iterator it = lst.begin(); it != lst.end(); ++it )
364 (*it)->setParent( this );
368 \brief Get the parent object.
369 \return parent object or 0 if this is top-level item
371 SUIT_DataObject* SUIT_DataObject::parent() const
377 \brief Change the parent object.
378 \param p new parent object
380 void SUIT_DataObject::setParent( SUIT_DataObject* p )
386 parent()->removeChild( this );
391 parent()->appendChild( this );
394 void SUIT_DataObject::assignParent( SUIT_DataObject* p )
403 \brief Sets modification state of the object.
405 When the object has been modified (modified is set to true)
406 a signal is emitted to notify the tree model and eventually redraw the data object.
408 \param modified modified state
410 void SUIT_DataObject::setModified(bool modified)
412 if ( _modified == modified )
415 _modified = modified;
417 signal()->emitModified( this );
421 \brief Get data object name.
423 This method should be re-implemented in the subclasses.
424 Default implementation returns null string.
428 QString SUIT_DataObject::name() const
434 \brief Get object text data for the specified column.
436 This method can be re-implemented in the subclasses.
437 Default implementation returns null string.
439 Column with \a id = 0 (NameId) is supposed to be used
440 to get the object name (as it does the default implementation).
443 \return object text data
445 QString SUIT_DataObject::text( const int id ) const
447 return id == NameId ? name() : QString();
451 \brief Get data object icon for the specified column.
453 This method can be re-implemented in the subclasses.
454 Default implementation returns null pixmap.
456 The parameter \a id specifies the column identificator
459 \return object icon for the specified column
461 QPixmap SUIT_DataObject::icon( const int /*id*/ ) const
467 \brief Get data object color for the specified column.
469 This method can be re-implemented in the subclasses.
470 Default implementation returns null color.
472 The parameter \a id specifies the column identificator
474 \param role color role
476 \return object color for the specified column
478 QColor SUIT_DataObject::color( const ColorRole /*role*/, const int /*id*/ ) const
484 \brief Get data object tooltip for the specified column.
486 This method can be re-implemented in the subclasses.
487 Default implementation returns null string.
489 The parameter \a id specifies the column identificator
490 (to display, for example, in the tree view widget).
493 \return object tooltip for the specified column
495 QString SUIT_DataObject::toolTip( const int /*id*/ ) const
501 \brief Get data object status tip for the specified column.
503 This method can be re-implemented in the subclasses.
504 Default implementation returns null string.
506 The parameter \a id specifies the column identificator
509 \return object status tip for the specified column
511 QString SUIT_DataObject::statusTip( const int /*id*/ ) const
517 \brief Get data object "what's this" information for the
520 This method can be re-implemented in the subclasses.
521 Default implementation returns null string.
523 The parameter \a id specifies the column identificator
526 \return object "what's this" information for the specified column
528 QString SUIT_DataObject::whatsThis( const int /*id*/ ) const
534 \brief Get data object font for the specified column.
536 This method can be re-implemented in the subclasses.
537 Default implementation returns application default font.
539 The parameter \a id specifies the column identificator
542 \return object font for the specified column
544 QFont SUIT_DataObject::font( const int /*id*/ ) const
550 \brief Get data object text alignment for the specified column.
552 This method can be re-implemented in the subclasses.
553 Default implementation returns default alignment which
556 The parameter \a id specifies the column identificator
557 (to display, for example, in the tree view widget).
560 \return object text alignment flags for the specified column
562 int SUIT_DataObject::alignment( const int /*id*/ ) const
564 return Qt::AlignLeft;
567 bool SUIT_DataObject::expandable() const
573 \brief Check if the object is visible.
575 This method can be re-implemented in the subclasses.
576 Default implementation returns \c true (all objects are visible by default).
578 \return \c true if this object is displayable or \c false otherwise
580 bool SUIT_DataObject::isVisible() const
586 \brief Check if the object is draggable.
588 This method can be re-implemented in the subclasses.
589 Default implementation returns \c false (all objects could not be dragged).
591 \return \c true if it is possible to drag this object
593 bool SUIT_DataObject::isDraggable() const
599 \brief Check if the drop operation for this object is possible.
601 This method can be re-implemented in the subclasses.
602 Default implementation returns \c false (drop operation is not allowed).
604 \return \c true if it is possible to drop one or more objects (currently selected) to this object
606 bool SUIT_DataObject::isDropAccepted() const
612 \brief Check if this object is enabled.
614 This method can be re-implemented in the subclasses.
615 Default implementation returns \c true (all objects are enabled).
617 \return \c true if the user can interact with the item
619 bool SUIT_DataObject::isEnabled() const
625 \brief Check if this object is selectable.
627 This method can be re-implemented in the subclasses.
628 Default implementation returns \c true (all objects are selectable).
630 \return \c true if the item can be selected
632 bool SUIT_DataObject::isSelectable() const
638 \brief Check if this object is checkable for the specified column.
640 This method can be re-implemented in the subclasses.
641 Default implementation returns \c false (all objects are not checkable).
644 \return \c true if the item can be checked or unchecked by the user
647 bool SUIT_DataObject::isCheckable( const int /*id*/ ) const
653 \brief Check if this object is can't be renamed in place
655 This method can be re-implemented in the subclasses.
656 Default implementation returns \c false (all objects can not be renamed).
659 \return \c true if the item can be renamed by the user in place (e.g. in the Object browser)
661 bool SUIT_DataObject::renameAllowed( const int /*id*/ ) const
667 \brief Set name of the this object.
669 This method can be re-implemented in the subclasses.
670 Default implementation returns \c false.
672 \return \c true if rename operation finished successfully, \c false otherwise.
674 bool SUIT_DataObject::setName(const QString& /*name*/) {
679 \brief Get the checked state of the object (if it is checkable)
680 for the specified column.
682 Default implementation supports the checked state for the first
683 ("Name") column only.
686 \return checked state of the object for the specified column
687 \sa setOn(), isCheckable()
689 bool SUIT_DataObject::isOn( const int id ) const
691 return id == NameId && myCheck;
695 \brief Set the checked state of the object (if it is checkable)
696 for the specified column.
698 Default implementation supports the checked state for the first
699 ("Name") column only.
701 \param on new checked state of the object for the specified column
703 \sa isOn(), isCheckable()
705 void SUIT_DataObject::setOn( const bool on, const int id )
712 \brief Get the "opened" state of the object.
713 \return "opened" state of the object
716 bool SUIT_DataObject::isOpen() const
722 \brief Set the "opened" state of the object.
723 \param on new "opened" state of the object
726 void SUIT_DataObject::setOpen( const bool on )
732 \brief Check if the specified column supports custom sorting.
734 This method can be re-implemented in the subclasses.
735 Default implementation returns false ("Name" column does not require
739 \return \c true if column sorting should be customized
742 bool SUIT_DataObject::customSorting( const int /*id*/ ) const
748 \brief Compares data from two items for sorting purposes.
750 This method can be re-implemented in the subclasses.
751 Default implementation returns false ("Name" column does not require
754 This method is called only for those columns for which customSorting()
755 method returns \c true.
757 \param left first data to compare
758 \param right second data to compare
760 \return result of the comparison
763 bool SUIT_DataObject::compare( const QVariant& /*left*/, const QVariant& /*right*/,
764 const int /*id*/ ) const
770 \brief Get the object unique indentification key.
772 This method can be re-implemented in the subclasses.
773 Default implementation returns 0.
777 SUIT_DataObjectKey* SUIT_DataObject::key() const
783 \brief Get global signal handler.
784 \return the only instance of the signal handler
786 SUIT_DataObject::Signal* SUIT_DataObject::signal()
789 mySignal = new Signal();
794 \brief Connect to the signal handlerx
795 \param sig signal name
796 \param reciever signal receiver object
797 \param slot slot name
798 \return \c true if connection is successfull
800 bool SUIT_DataObject::connect( const char* sig, QObject* reciever, const char* slot )
802 if ( !reciever || !slot )
805 signal()->disconnect( signal(), sig, reciever, slot );
806 return signal()->connect( signal(), sig, reciever, slot );
810 \brief Disconnect from the signal handler
811 \param sig signal name
812 \param reciever signal receiver object
813 \param slot slot name
814 \return \c true if disconnection is successfull
816 bool SUIT_DataObject::disconnect( const char* sig, QObject* reciever, const char* slot )
818 if ( !reciever || !slot )
820 return signal()->disconnect( signal(), sig, reciever, slot );
824 \brief Schedule this object for the late deleting.
826 The object will be deleted when control returns to the event loop.
827 Note that entering and leaving a new event loop (e.g., by opening
828 a modal dialog) will not perform the deferred deletion; for the object
829 to be deleted, the control must return to the event loop from which
830 deleteLater() was called.
832 void SUIT_DataObject::deleteLater()
835 parent()->removeChild( this, false ); // to avoid infinite loop!
836 signal()->deleteLater( this );
840 \brief Dump the object tree recursively to the standard output.
841 \param indent current indentation level
843 void SUIT_DataObject::dump( const int indent ) const
845 QString strIndent = QString().fill( ' ', indent ); // indentation string
846 printf( "%s%s\n", strIndent.toLatin1().data(), name().toLatin1().data() );
847 for ( DataObjectList::const_iterator it = myChildren.begin(); it != myChildren.end(); ++it )
848 (*it)->dump( indent + 2 );
852 \class SUIT_DataObject::Signal
853 \brief Watcher class, responsible for the emitting signals on behalf of
856 SUIT_DataObject class does not inherit from QObject for the performance
857 reasons, so it can not use signals/slots mechanism directly.
858 Instead it uses the only Signal object to emit the signals when the data
859 object is created, destroyed, inserted to the parent object or removed
862 If some object needs to handle, for example, data object destroying, it can
863 use SUIT_DataObject::signal() method to connect the signal:
865 MyHandler* h = new MyHandler();
866 h->connect( SUIT_DataObject::signal(), SIGNAL(destroyed(SUIT_DataObject*)),
867 h, SLOT(onDestroyed(SUIT_DataObject*)) );
869 The same can be done by using static method SUIT_DataObject::connect().
872 MyHandler* h = new MyHandler();
873 SUIT_DataObject::connect( SIGNAL(destroyed(SUIT_DataObject*)),
874 h, SLOT(onDestroyed(SUIT_DataObject*)));
881 SUIT_DataObject::Signal::Signal()
889 Destroys data object which are scheduled for the deleting with the deleteLater().
891 SUIT_DataObject::Signal::~Signal()
893 for ( DataObjectList::Iterator it = myDelLaterObjects.begin();
894 it != myDelLaterObjects.end(); ++it ) {
897 myDelLaterObjects.clear();
901 \brief Emit signal about data object creation.
902 \param object data object being created
904 void SUIT_DataObject::Signal::emitCreated( SUIT_DataObject* object )
907 emit created( object );
911 \brief Emit signal about data object destroying.
912 \param object data object being destroyed
914 void SUIT_DataObject::Signal::emitDestroyed( SUIT_DataObject* object )
917 if ( myDelLaterObjects.contains( object ) )
918 // object is being destroyed after calling deleteLater():
919 // the signal has been already emitted from deleteLater()
920 // we should avoid repeating of the object destroying from
921 // the Signal destructor
922 myDelLaterObjects.removeAll( object );
924 // object is being destroyed directly or via deleteLater()
925 emit destroyed( object );
930 \brief Emit signal about data object adding to the parent data object.
931 \param object data object being added
932 \param parent parent data object
934 void SUIT_DataObject::Signal::emitInserted( SUIT_DataObject* object, SUIT_DataObject* parent )
936 emit( inserted( object, parent ) );
940 \brief Emit signal about data object removed from the parent data object.
941 \param object data object being removed
942 \param parent parent data object
944 void SUIT_DataObject::Signal::emitRemoved( SUIT_DataObject* object, SUIT_DataObject* parent )
946 emit( removed( object, parent ) );
950 \brief Emit a signal to notify that the data object has been modified.
951 \param object data object that has been modified
953 void SUIT_DataObject::Signal::emitModified( SUIT_DataObject* object )
955 emit( modified( object ) );
959 \brief Schedule data object for the late deleting.
960 \param object data object to be deleted later
962 void SUIT_DataObject::Signal::deleteLater( SUIT_DataObject* object )
964 if ( !myDelLaterObjects.contains( object ) ) {
965 emitDestroyed( object );
966 myDelLaterObjects.append( object );
971 \brief Updates necessary internal fields of data object
973 void SUIT_DataObject::update()
978 \brief return unique group identificator
980 Groups of data objects are used for column information search.
981 Each column of data model has one or several registered group id
982 If object has the same group id as one of registered, the information
983 will be shown; the custom id of column will be passed into data() method
984 in order to identify column from point of view of data object
987 int SUIT_DataObject::groupId() const
992 \brief return custom data for data object.
994 QVariant SUIT_DataObject::customData(Qtx::CustomDataType /*type*/) {
998 \fn void SUIT_DataObject::Signal::created( SUIT_DataObject* object );
999 \brief Emitted when data object is created.
1000 \param object data object being created
1004 \fn void SUIT_DataObject::Signal::destroyed( SUIT_DataObject* object );
1005 \brief Emitted when data object is destroyed.
1006 \param object data object being destroyed
1010 \fn void SUIT_DataObject::Signal::inserted( SUIT_DataObject* object, SUIT_DataObject* parent );
1011 \brief Emitted when data object is inserted to the parent data object.
1012 \param object data object being created
1013 \param parent parent data object
1017 \fn void SUIT_DataObject::Signal::removed( SUIT_DataObject* object, SUIT_DataObject* parent );
1018 \brief Emitted when data object is removed from the parent data object.
1019 \param object data object being removed
1020 \param parent parent data object