1 // Copyright (C) 2007-2015 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, or (at your option) any later version.
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 Moves the child position from current to new one.
143 \param theObj child object
144 \param theNewPos child objectnew position in the children list
147 void SUIT_DataObject::moveChildPos( SUIT_DataObject* theObj, int theNewPos)
149 if (myChildren.size() <= 1) return;
151 int aNewPos = theNewPos;
152 if (aNewPos < 0) aNewPos = 0;
153 if (aNewPos > (myChildren.size() - 1)) aNewPos = myChildren.size() - 1;
155 if (myChildren.removeOne(theObj))
156 myChildren.insert(aNewPos, theObj);
161 \brief Get child object by the specified index.
162 \param idx child object index
163 \return child object or 0 if index is out of range
165 SUIT_DataObject* SUIT_DataObject::childObject( const int idx ) const
167 SUIT_DataObject* child = 0;
169 if ( idx >= 0 && idx < myChildren.count() )
170 child = myChildren.at( idx );
176 \brief Get the object level in the tree structure.
178 Root object has level 0.
180 \return object level.
182 int SUIT_DataObject::level() const
185 SUIT_DataObject* p = parent();
194 \brief Get the position of the data object in its parent's children list
195 \return data object position
197 int SUIT_DataObject::position() const
199 return myParent ? myParent->childPos( this ) : 0;
203 \brief Sets new position of the object in parent's list
205 void SUIT_DataObject::setPosition(int theNewPos)
207 if (theNewPos == position()) return;
208 if (!myParent) return;
209 myParent->moveChildPos(this, theNewPos);
213 \brief Get the next sibling data object in the children list.
214 \return child object or 0 if there is no next sibling
217 SUIT_DataObject* SUIT_DataObject::nextBrother() const
219 return myParent ? myParent->childObject( myParent->childPos( this ) + 1 ) : 0;
223 \brief Get the previous sibling data object in the children list.
224 \return child object or 0 if there is no previous sibling
227 SUIT_DataObject* SUIT_DataObject::prevBrother() const
229 return myParent ? myParent->childObject( myParent->childPos( this ) - 1 ) : 0;
233 \brief Get "auto-delete children" flag.
234 \return \c true if the object should delete all its children on destroying
235 \sa setAutoDeleteChildren()
237 bool SUIT_DataObject::autoDeleteChildren() const
243 \brief Set "auto-delete children" flag.
245 If this flag is on (default), the object will delete
246 all its children on destroying.
248 \param on new flag value
249 \sa autoDeleteChildren()
251 void SUIT_DataObject::setAutoDeleteChildren( const bool on )
257 \brief Get all children.
259 If parameter \a rec is \c true then function collects all
260 the children recursively.
262 \param lst returning list of children
263 \param rec if \c true collect all children recursively
265 void SUIT_DataObject::children( DataObjectList& lst, const bool rec ) const
267 for ( DataObjectList::const_iterator it = myChildren.begin(); it != myChildren.end(); ++it )
271 (*it)->children( lst, rec );
276 \brief Get all children.
279 If parameter \a rec is \c true then function collects all
280 the children recursively.
282 \param rec if \c true collect all children recursively
283 \return list of children
285 DataObjectList SUIT_DataObject::children( const bool rec )
288 children( lst, rec );
293 \brief Add new child object to the end of the children list.
294 \param obj child object being added
296 void SUIT_DataObject::appendChild( SUIT_DataObject* obj )
298 insertChild( obj, myChildren.count() );
302 \brief Insert new child object to the list of the children.
303 \param obj child object being added
304 \param position child position
306 void SUIT_DataObject::insertChild( SUIT_DataObject* obj, int position )
308 if ( !obj || myChildren.contains( obj ) )
311 int pos = position < 0 ? myChildren.count() : position;
312 myChildren.insert( qMin( pos, (int)myChildren.count() ), obj );
313 obj->setParent( this );
314 signal()->emitInserted( obj, this );
318 \brief Insert new child object into the list of the children (faster version of insertChild without signal).
319 \param obj child object being added
320 \param position child position
322 void SUIT_DataObject::insertChildAtPos( SUIT_DataObject* obj, int position )
325 int pos = position < 0 ? myChildren.count() : position;
326 myChildren.insert( qMin( pos, (int)myChildren.count() ), obj );
327 obj->assignParent( this );
331 \brief Remove the specified child object reference.
332 \param obj child object being removed
333 \param del if \c true, the child object is destroyed
335 void SUIT_DataObject::removeChild( SUIT_DataObject* obj, const bool del )
340 if ( myChildren.removeAll( obj ) ) {
341 signal()->emitRemoved( obj, this );
350 \brief Replace the specified child object by another object.
351 \param src child object being replaced
352 \param trg new child object
353 \param del if \c true, the previous object is destroyed
354 \return \c true if the object has been replaced
356 bool SUIT_DataObject::replaceChild( SUIT_DataObject* src, SUIT_DataObject* trg, const bool del )
361 int idx = childPos( trg );
364 int pos = childPos( src );
368 insertChild( trg, idx );
372 insertChild( trg, pos );
382 \brief Change the parent for all children from specified object to this one.
383 \param obj object which children to be reparented
385 void SUIT_DataObject::reparentChildren( const SUIT_DataObject* obj )
391 obj->children( lst );
392 for ( DataObjectList::iterator it = lst.begin(); it != lst.end(); ++it )
393 (*it)->setParent( this );
397 \brief Get the parent object.
398 \return parent object or 0 if this is top-level item
400 SUIT_DataObject* SUIT_DataObject::parent() const
406 \brief Change the parent object.
407 \param p new parent object
409 void SUIT_DataObject::setParent( SUIT_DataObject* p )
415 parent()->removeChild( this );
420 parent()->appendChild( this );
423 void SUIT_DataObject::assignParent( SUIT_DataObject* p )
432 \brief Sets modification state of the object.
434 When the object has been modified (modified is set to true)
435 a signal is emitted to notify the tree model and eventually redraw the data object.
437 \param modified modified state
439 void SUIT_DataObject::setModified(bool modified)
441 if ( _modified == modified )
444 _modified = modified;
446 signal()->emitModified( this );
450 \brief Get data object name.
452 This method should be re-implemented in the subclasses.
453 Default implementation returns null string.
457 QString SUIT_DataObject::name() const
463 \brief Get object text data for the specified column.
465 This method can be re-implemented in the subclasses.
466 Default implementation returns null string.
468 Column with \a id = 0 (NameId) is supposed to be used
469 to get the object name (as it does the default implementation).
472 \return object text data
474 QString SUIT_DataObject::text( const int id ) const
476 return id == NameId ? name() : QString();
480 \brief Get data object icon for the specified column.
482 This method can be re-implemented in the subclasses.
483 Default implementation returns null pixmap.
485 The parameter \a id specifies the column identificator
488 \return object icon for the specified column
490 QPixmap SUIT_DataObject::icon( const int /*id*/ ) const
496 \brief Get data object color for the specified column.
498 This method can be re-implemented in the subclasses.
499 Default implementation returns null color.
501 The parameter \a id specifies the column identificator
503 \param role color role
505 \return object color for the specified column
507 QColor SUIT_DataObject::color( const ColorRole /*role*/, const int /*id*/ ) const
513 \brief Get data object tooltip for the specified column.
515 This method can be re-implemented in the subclasses.
516 Default implementation returns null string.
518 The parameter \a id specifies the column identificator
519 (to display, for example, in the tree view widget).
522 \return object tooltip for the specified column
524 QString SUIT_DataObject::toolTip( const int /*id*/ ) const
530 \brief Get data object status tip for the specified column.
532 This method can be re-implemented in the subclasses.
533 Default implementation returns null string.
535 The parameter \a id specifies the column identificator
538 \return object status tip for the specified column
540 QString SUIT_DataObject::statusTip( const int /*id*/ ) const
546 \brief Get data object "what's this" information for the
549 This method can be re-implemented in the subclasses.
550 Default implementation returns null string.
552 The parameter \a id specifies the column identificator
555 \return object "what's this" information for the specified column
557 QString SUIT_DataObject::whatsThis( const int /*id*/ ) const
563 \brief Get data object font for the specified column.
565 This method can be re-implemented in the subclasses.
566 Default implementation returns application default font.
568 The parameter \a id specifies the column identificator
571 \return object font for the specified column
573 QFont SUIT_DataObject::font( const int /*id*/ ) const
579 \brief Get data object text alignment for the specified column.
581 This method can be re-implemented in the subclasses.
582 Default implementation returns default alignment which
585 The parameter \a id specifies the column identificator
586 (to display, for example, in the tree view widget).
589 \return object text alignment flags for the specified column
591 int SUIT_DataObject::alignment( const int /*id*/ ) const
593 return Qt::AlignLeft;
596 bool SUIT_DataObject::expandable() const
602 \brief Check if the object is visible.
604 This method can be re-implemented in the subclasses.
605 Default implementation returns \c true (all objects are visible by default).
607 \return \c true if this object is displayable or \c false otherwise
609 bool SUIT_DataObject::isVisible() const
615 \brief Check if the object is draggable.
617 This method can be re-implemented in the subclasses.
618 Default implementation returns \c false (all objects could not be dragged).
620 \return \c true if it is possible to drag this object
622 bool SUIT_DataObject::isDraggable() const
628 \brief Check if the drop operation for this object is possible.
630 This method can be re-implemented in the subclasses.
631 Default implementation returns \c false (drop operation is not allowed).
633 \return \c true if it is possible to drop one or more objects (currently selected) to this object
635 bool SUIT_DataObject::isDropAccepted() const
641 \brief Check if this object is enabled.
643 This method can be re-implemented in the subclasses.
644 Default implementation returns \c true (all objects are enabled).
646 \return \c true if the user can interact with the item
648 bool SUIT_DataObject::isEnabled() const
654 \brief Check if this object is selectable.
656 This method can be re-implemented in the subclasses.
657 Default implementation returns \c true (all objects are selectable).
659 \return \c true if the item can be selected
661 bool SUIT_DataObject::isSelectable() const
667 \brief Check if this object is checkable for the specified column.
669 This method can be re-implemented in the subclasses.
670 Default implementation returns \c false (all objects are not checkable).
673 \return \c true if the item can be checked or unchecked by the user
676 bool SUIT_DataObject::isCheckable( const int /*id*/ ) const
682 \brief Check if this object is can't be renamed in place
684 This method can be re-implemented in the subclasses.
685 Default implementation returns \c false (all objects can not be renamed).
688 \return \c true if the item can be renamed by the user in place (e.g. in the Object browser)
690 bool SUIT_DataObject::renameAllowed( const int /*id*/ ) const
696 \brief Set name of the this object.
698 This method can be re-implemented in the subclasses.
699 Default implementation returns \c false.
701 \return \c true if rename operation finished successfully, \c false otherwise.
703 bool SUIT_DataObject::setName(const QString& /*name*/) {
708 \brief Get the checked state of the object (if it is checkable)
709 for the specified column.
711 Default implementation supports the checked state for the first
712 ("Name") column only.
715 \return checked state of the object for the specified column
716 \sa setOn(), isCheckable()
718 bool SUIT_DataObject::isOn( const int id ) const
720 return id == NameId && myCheck;
724 \brief Set the checked state of the object (if it is checkable)
725 for the specified column.
727 Default implementation supports the checked state for the first
728 ("Name") column only.
730 \param on new checked state of the object for the specified column
732 \sa isOn(), isCheckable()
734 void SUIT_DataObject::setOn( const bool on, const int id )
741 \brief Get the "opened" state of the object.
742 \return "opened" state of the object
745 bool SUIT_DataObject::isOpen() const
751 \brief Set the "opened" state of the object.
752 \param on new "opened" state of the object
755 void SUIT_DataObject::setOpen( const bool on )
761 \brief Check if the specified column supports custom sorting.
763 This method can be re-implemented in the subclasses.
764 Default implementation returns false ("Name" column does not require
768 \return \c true if column sorting should be customized
771 bool SUIT_DataObject::customSorting( const int /*id*/ ) const
777 \brief Compares data from two items for sorting purposes.
779 This method can be re-implemented in the subclasses.
780 Default implementation returns false ("Name" column does not require
783 This method is called only for those columns for which customSorting()
784 method returns \c true.
786 \param left first data to compare
787 \param right second data to compare
789 \return result of the comparison
792 bool SUIT_DataObject::compare( const QVariant& /*left*/, const QVariant& /*right*/,
793 const int /*id*/ ) const
799 \brief Get the object unique indentification key.
801 This method can be re-implemented in the subclasses.
802 Default implementation returns 0.
806 SUIT_DataObjectKey* SUIT_DataObject::key() const
812 \brief Get global signal handler.
813 \return the only instance of the signal handler
815 SUIT_DataObject::Signal* SUIT_DataObject::signal()
818 mySignal = new Signal();
823 \brief Connect to the signal handlerx
824 \param sig signal name
825 \param reciever signal receiver object
826 \param slot slot name
827 \return \c true if connection is successfull
829 bool SUIT_DataObject::connect( const char* sig, QObject* reciever, const char* slot )
831 if ( !reciever || !slot )
834 signal()->disconnect( signal(), sig, reciever, slot );
835 return signal()->connect( signal(), sig, reciever, slot );
839 \brief Disconnect from the signal handler
840 \param sig signal name
841 \param reciever signal receiver object
842 \param slot slot name
843 \return \c true if disconnection is successfull
845 bool SUIT_DataObject::disconnect( const char* sig, QObject* reciever, const char* slot )
847 if ( !reciever || !slot )
849 return signal()->disconnect( signal(), sig, reciever, slot );
853 \brief Schedule this object for the late deleting.
855 The object will be deleted when control returns to the event loop.
856 Note that entering and leaving a new event loop (e.g., by opening
857 a modal dialog) will not perform the deferred deletion; for the object
858 to be deleted, the control must return to the event loop from which
859 deleteLater() was called.
861 void SUIT_DataObject::deleteLater()
864 parent()->removeChild( this, false ); // to avoid infinite loop!
865 signal()->deleteLater( this );
869 \brief Dump the object tree recursively to the standard output.
870 \param indent current indentation level
872 void SUIT_DataObject::dump( const int indent ) const
874 QString strIndent = QString().fill( ' ', indent ); // indentation string
875 printf( "%s%s\n", strIndent.toLatin1().data(), name().toLatin1().data() );
876 for ( DataObjectList::const_iterator it = myChildren.begin(); it != myChildren.end(); ++it )
877 (*it)->dump( indent + 2 );
881 \class SUIT_DataObject::Signal
882 \brief Watcher class, responsible for the emitting signals on behalf of
885 SUIT_DataObject class does not inherit from QObject for the performance
886 reasons, so it can not use signals/slots mechanism directly.
887 Instead it uses the only Signal object to emit the signals when the data
888 object is created, destroyed, inserted to the parent object or removed
891 If some object needs to handle, for example, data object destroying, it can
892 use SUIT_DataObject::signal() method to connect the signal:
894 MyHandler* h = new MyHandler();
895 h->connect( SUIT_DataObject::signal(), SIGNAL(destroyed(SUIT_DataObject*)),
896 h, SLOT(onDestroyed(SUIT_DataObject*)) );
898 The same can be done by using static method SUIT_DataObject::connect().
901 MyHandler* h = new MyHandler();
902 SUIT_DataObject::connect( SIGNAL(destroyed(SUIT_DataObject*)),
903 h, SLOT(onDestroyed(SUIT_DataObject*)));
910 SUIT_DataObject::Signal::Signal()
918 Destroys data object which are scheduled for the deleting with the deleteLater().
920 SUIT_DataObject::Signal::~Signal()
922 for ( DataObjectList::Iterator it = myDelLaterObjects.begin();
923 it != myDelLaterObjects.end(); ++it ) {
926 myDelLaterObjects.clear();
930 \brief Emit signal about data object creation.
931 \param object data object being created
933 void SUIT_DataObject::Signal::emitCreated( SUIT_DataObject* object )
936 emit created( object );
940 \brief Emit signal about data object destroying.
941 \param object data object being destroyed
943 void SUIT_DataObject::Signal::emitDestroyed( SUIT_DataObject* object )
946 if ( myDelLaterObjects.contains( object ) )
947 // object is being destroyed after calling deleteLater():
948 // the signal has been already emitted from deleteLater()
949 // we should avoid repeating of the object destroying from
950 // the Signal destructor
951 myDelLaterObjects.removeAll( object );
953 // object is being destroyed directly or via deleteLater()
954 emit destroyed( object );
959 \brief Emit signal about data object adding to the parent data object.
960 \param object data object being added
961 \param parent parent data object
963 void SUIT_DataObject::Signal::emitInserted( SUIT_DataObject* object, SUIT_DataObject* parent )
965 emit( inserted( object, parent ) );
969 \brief Emit signal about data object removed from the parent data object.
970 \param object data object being removed
971 \param parent parent data object
973 void SUIT_DataObject::Signal::emitRemoved( SUIT_DataObject* object, SUIT_DataObject* parent )
975 emit( removed( object, parent ) );
979 \brief Emit a signal to notify that the data object has been modified.
980 \param object data object that has been modified
982 void SUIT_DataObject::Signal::emitModified( SUIT_DataObject* object )
984 emit( modified( object ) );
988 \brief Schedule data object for the late deleting.
989 \param object data object to be deleted later
991 void SUIT_DataObject::Signal::deleteLater( SUIT_DataObject* object )
993 if ( !myDelLaterObjects.contains( object ) ) {
994 emitDestroyed( object );
995 myDelLaterObjects.append( object );
1000 \brief Updates necessary internal fields of data object
1002 void SUIT_DataObject::update()
1007 \brief return unique group identificator
1009 Groups of data objects are used for column information search.
1010 Each column of data model has one or several registered group id
1011 If object has the same group id as one of registered, the information
1012 will be shown; the custom id of column will be passed into data() method
1013 in order to identify column from point of view of data object
1016 int SUIT_DataObject::groupId() const
1021 \brief return custom data for data object.
1023 QVariant SUIT_DataObject::customData(Qtx::CustomDataType /*type*/) {
1027 \fn void SUIT_DataObject::Signal::created( SUIT_DataObject* object );
1028 \brief Emitted when data object is created.
1029 \param object data object being created
1033 \fn void SUIT_DataObject::Signal::destroyed( SUIT_DataObject* object );
1034 \brief Emitted when data object is destroyed.
1035 \param object data object being destroyed
1039 \fn void SUIT_DataObject::Signal::inserted( SUIT_DataObject* object, SUIT_DataObject* parent );
1040 \brief Emitted when data object is inserted to the parent data object.
1041 \param object data object being created
1042 \param parent parent data object
1046 \fn void SUIT_DataObject::Signal::removed( SUIT_DataObject* object, SUIT_DataObject* parent );
1047 \brief Emitted when data object is removed from the parent data object.
1048 \param object data object being removed
1049 \param parent parent data object