1 // Copyright (C) 2007-2023 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 )
429 \brief Sets modification state of the object.
431 When the object has been modified (modified is set to true)
432 a signal is emitted to notify the tree model and eventually redraw the data object.
434 \param modified modified state
436 void SUIT_DataObject::setModified(bool modified)
438 if ( _modified == modified )
441 _modified = modified;
443 signal()->emitModified( this );
447 \brief Get data object name.
449 This method should be re-implemented in the subclasses.
450 Default implementation returns null string.
454 QString SUIT_DataObject::name() const
460 \brief Get object text data for the specified column.
462 This method can be re-implemented in the subclasses.
463 Default implementation returns null string.
465 Column with \a id = 0 (NameId) is supposed to be used
466 to get the object name (as it does the default implementation).
469 \return object text data
471 QString SUIT_DataObject::text( const int id ) const
473 return id == NameId ? name() : QString();
477 \brief Get data object icon for the specified column.
479 This method can be re-implemented in the subclasses.
480 Default implementation returns null pixmap.
482 The parameter \a id specifies the column identificator
485 \return object icon for the specified column
487 QPixmap SUIT_DataObject::icon( const int /*id*/ ) const
493 \brief Get data object color for the specified column.
495 This method can be re-implemented in the subclasses.
496 Default implementation returns null color.
498 The parameter \a id specifies the column identificator
500 \param role color role
502 \return object color for the specified column
504 QColor SUIT_DataObject::color( const ColorRole /*role*/, const int /*id*/ ) const
510 \brief Get data object tooltip for the specified column.
512 This method can be re-implemented in the subclasses.
513 Default implementation returns null string.
515 The parameter \a id specifies the column identificator
516 (to display, for example, in the tree view widget).
519 \return object tooltip for the specified column
521 QString SUIT_DataObject::toolTip( const int /*id*/ ) const
527 \brief Get data object status tip for the specified column.
529 This method can be re-implemented in the subclasses.
530 Default implementation returns null string.
532 The parameter \a id specifies the column identificator
535 \return object status tip for the specified column
537 QString SUIT_DataObject::statusTip( const int /*id*/ ) const
543 \brief Get data object "what's this" information for the
546 This method can be re-implemented in the subclasses.
547 Default implementation returns null string.
549 The parameter \a id specifies the column identificator
552 \return object "what's this" information for the specified column
554 QString SUIT_DataObject::whatsThis( const int /*id*/ ) const
560 \brief Get data object font for the specified column.
562 This method can be re-implemented in the subclasses.
563 Default implementation returns application default font.
565 The parameter \a id specifies the column identificator
568 \return object font for the specified column
570 QFont SUIT_DataObject::font( const int /*id*/ ) const
576 \brief Get data object text alignment for the specified column.
578 This method can be re-implemented in the subclasses.
579 Default implementation returns default alignment which
582 The parameter \a id specifies the column identificator
583 (to display, for example, in the tree view widget).
586 \return object text alignment flags for the specified column
588 int SUIT_DataObject::alignment( const int /*id*/ ) const
590 return Qt::AlignLeft;
593 bool SUIT_DataObject::expandable() const
599 \brief Check if the object is visible.
601 This method can be re-implemented in the subclasses.
602 Default implementation returns \c true (all objects are visible by default).
604 \return \c true if this object is displayable or \c false otherwise
606 bool SUIT_DataObject::isVisible() const
612 \brief Check if the object is draggable.
614 This method can be re-implemented in the subclasses.
615 Default implementation returns \c false (all objects could not be dragged).
617 \return \c true if it is possible to drag this object
619 bool SUIT_DataObject::isDraggable() const
625 \brief Check if the drop operation for this object is possible.
627 This method can be re-implemented in the subclasses.
628 Default implementation returns \c false (drop operation is not allowed).
630 \return \c true if it is possible to drop one or more objects (currently selected) to this object
632 bool SUIT_DataObject::isDropAccepted() const
638 \brief Check if this object is enabled.
640 This method can be re-implemented in the subclasses.
641 Default implementation returns \c true (all objects are enabled).
643 \return \c true if the user can interact with the item
645 bool SUIT_DataObject::isEnabled() const
651 \brief Check if this object is selectable.
653 This method can be re-implemented in the subclasses.
654 Default implementation returns \c true (all objects are selectable).
656 \return \c true if the item can be selected
658 bool SUIT_DataObject::isSelectable() const
664 \brief Check if this object is checkable for the specified column.
666 This method can be re-implemented in the subclasses.
667 Default implementation returns \c false (all objects are not checkable).
670 \return \c true if the item can be checked or unchecked by the user
673 bool SUIT_DataObject::isCheckable( const int /*id*/ ) const
679 \brief Check if this object is can't be renamed in place
681 This method can be re-implemented in the subclasses.
682 Default implementation returns \c false (all objects can not be renamed).
685 \return \c true if the item can be renamed by the user in place (e.g. in the Object browser)
687 bool SUIT_DataObject::renameAllowed( const int /*id*/ ) const
693 \brief Set name of the this object.
695 This method can be re-implemented in the subclasses.
696 Default implementation returns \c false.
698 \return \c true if rename operation finished successfully, \c false otherwise.
700 bool SUIT_DataObject::setName(const QString& /*name*/) {
705 \brief Get the checked state of the object (if it is checkable)
706 for the specified column.
708 Default implementation supports the checked state for the first
709 ("Name") column only.
712 \return checked state of the object for the specified column
713 \sa setOn(), isCheckable()
715 bool SUIT_DataObject::isOn( const int id ) const
717 return id == NameId && myCheck;
721 \brief Set the checked state of the object (if it is checkable)
722 for the specified column.
724 Default implementation supports the checked state for the first
725 ("Name") column only.
727 \param on new checked state of the object for the specified column
729 \sa isOn(), isCheckable()
731 void SUIT_DataObject::setOn( const bool on, const int id )
738 \brief Get the "opened" state of the object.
739 \return "opened" state of the object
742 bool SUIT_DataObject::isOpen() const
748 \brief Set the "opened" state of the object.
749 \param on new "opened" state of the object
752 void SUIT_DataObject::setOpen( const bool on )
758 \brief Check if the specified column supports custom sorting.
760 This method can be re-implemented in the subclasses.
761 Default implementation returns false ("Name" column does not require
765 \return \c true if column sorting should be customized
768 bool SUIT_DataObject::customSorting( const int /*id*/ ) const
774 \brief Compares data from two items for sorting purposes.
776 This method can be re-implemented in the subclasses.
777 Default implementation returns false ("Name" column does not require
780 This method is called only for those columns for which customSorting()
781 method returns \c true.
783 \param left first data to compare
784 \param right second data to compare
786 \return result of the comparison
789 bool SUIT_DataObject::compare( const QVariant& /*left*/, const QVariant& /*right*/,
790 const int /*id*/ ) const
796 \brief Get the object unique indentification key.
798 This method can be re-implemented in the subclasses.
799 Default implementation returns 0.
803 SUIT_DataObjectKey* SUIT_DataObject::key() const
809 \brief Get global signal handler.
810 \return the only instance of the signal handler
812 SUIT_DataObject::Signal* SUIT_DataObject::signal()
815 mySignal = new Signal();
820 \brief Connect to the signal handlerx
821 \param sig signal name
822 \param reciever signal receiver object
823 \param slot slot name
824 \return \c true if connection is successfull
826 bool SUIT_DataObject::connect( const char* sig, QObject* reciever, const char* slot )
828 if ( !reciever || !slot )
831 signal()->disconnect( signal(), sig, reciever, slot );
832 return signal()->connect( signal(), sig, reciever, slot );
836 \brief Disconnect from the signal handler
837 \param sig signal name
838 \param reciever signal receiver object
839 \param slot slot name
840 \return \c true if disconnection is successfull
842 bool SUIT_DataObject::disconnect( const char* sig, QObject* reciever, const char* slot )
844 if ( !reciever || !slot )
846 return signal()->disconnect( signal(), sig, reciever, slot );
850 \brief Schedule this object for the late deleting.
852 The object will be deleted when control returns to the event loop.
853 Note that entering and leaving a new event loop (e.g., by opening
854 a modal dialog) will not perform the deferred deletion; for the object
855 to be deleted, the control must return to the event loop from which
856 deleteLater() was called.
858 void SUIT_DataObject::deleteLater()
861 parent()->removeChild( this, false ); // to avoid infinite loop!
862 signal()->deleteLater( this );
866 \brief Dump the object tree recursively to the standard output.
867 \param indent current indentation level
869 void SUIT_DataObject::dump( const int indent ) const
871 QString strIndent = QString().fill( ' ', indent ); // indentation string
872 printf( "%s%s\n", strIndent.toLatin1().data(), name().toLatin1().data() );
873 for ( DataObjectList::const_iterator it = myChildren.begin(); it != myChildren.end(); ++it )
874 (*it)->dump( indent + 2 );
878 \class SUIT_DataObject::Signal
879 \brief Watcher class, responsible for the emitting signals on behalf of
882 SUIT_DataObject class does not inherit from QObject for the performance
883 reasons, so it can not use signals/slots mechanism directly.
884 Instead it uses the only Signal object to emit the signals when the data
885 object is created, destroyed, inserted to the parent object or removed
888 If some object needs to handle, for example, data object destroying, it can
889 use SUIT_DataObject::signal() method to connect the signal:
891 MyHandler* h = new MyHandler();
892 h->connect( SUIT_DataObject::signal(), SIGNAL(destroyed(SUIT_DataObject*)),
893 h, SLOT(onDestroyed(SUIT_DataObject*)) );
895 The same can be done by using static method SUIT_DataObject::connect().
898 MyHandler* h = new MyHandler();
899 SUIT_DataObject::connect( SIGNAL(destroyed(SUIT_DataObject*)),
900 h, SLOT(onDestroyed(SUIT_DataObject*)));
907 SUIT_DataObject::Signal::Signal()
915 Destroys data object which are scheduled for the deleting with the deleteLater().
917 SUIT_DataObject::Signal::~Signal()
919 for ( DataObjectList::Iterator it = myDelLaterObjects.begin();
920 it != myDelLaterObjects.end(); ++it ) {
923 myDelLaterObjects.clear();
927 \brief Emit signal about data object creation.
928 \param object data object being created
930 void SUIT_DataObject::Signal::emitCreated( SUIT_DataObject* object )
933 emit created( object );
937 \brief Emit signal about data object destroying.
938 \param object data object being destroyed
940 void SUIT_DataObject::Signal::emitDestroyed( SUIT_DataObject* object )
943 if ( myDelLaterObjects.contains( object ) )
944 // object is being destroyed after calling deleteLater():
945 // the signal has been already emitted from deleteLater()
946 // we should avoid repeating of the object destroying from
947 // the Signal destructor
948 myDelLaterObjects.removeAll( object );
950 // object is being destroyed directly or via deleteLater()
951 emit destroyed( object );
956 \brief Emit signal about data object adding to the parent data object.
957 \param object data object being added
958 \param parent parent data object
960 void SUIT_DataObject::Signal::emitInserted( SUIT_DataObject* object, SUIT_DataObject* parent )
962 emit( inserted( object, parent ) );
966 \brief Emit signal about data object removed from the parent data object.
967 \param object data object being removed
968 \param parent parent data object
970 void SUIT_DataObject::Signal::emitRemoved( SUIT_DataObject* object, SUIT_DataObject* parent )
972 emit( removed( object, parent ) );
976 \brief Emit a signal to notify that the data object has been modified.
977 \param object data object that has been modified
979 void SUIT_DataObject::Signal::emitModified( SUIT_DataObject* object )
981 emit( modified( object ) );
985 \brief Schedule data object for the late deleting.
986 \param object data object to be deleted later
988 void SUIT_DataObject::Signal::deleteLater( SUIT_DataObject* object )
990 if ( !myDelLaterObjects.contains( object ) ) {
991 emitDestroyed( object );
992 myDelLaterObjects.append( object );
997 \brief Updates necessary internal fields of data object
999 void SUIT_DataObject::update()
1004 \brief return unique group identificator
1006 Groups of data objects are used for column information search.
1007 Each column of data model has one or several registered group id
1008 If object has the same group id as one of registered, the information
1009 will be shown; the custom id of column will be passed into data() method
1010 in order to identify column from point of view of data object
1013 int SUIT_DataObject::groupId() const
1018 \brief return custom data for data object.
1020 QVariant SUIT_DataObject::customData(Qtx::CustomDataType /*type*/) {
1024 \fn void SUIT_DataObject::Signal::created( SUIT_DataObject* object );
1025 \brief Emitted when data object is created.
1026 \param object data object being created
1030 \fn void SUIT_DataObject::Signal::destroyed( SUIT_DataObject* object );
1031 \brief Emitted when data object is destroyed.
1032 \param object data object being destroyed
1036 \fn void SUIT_DataObject::Signal::inserted( SUIT_DataObject* object, SUIT_DataObject* parent );
1037 \brief Emitted when data object is inserted to the parent data object.
1038 \param object data object being created
1039 \param parent parent data object
1043 \fn void SUIT_DataObject::Signal::removed( SUIT_DataObject* object, SUIT_DataObject* parent );
1044 \brief Emitted when data object is removed from the parent data object.
1045 \param object data object being removed
1046 \param parent parent data object