Salome HOME
Updated copyright comment
[modules/gui.git] / src / LightApp / LightApp_DataObject.cxx
index 9320c256d528ff3218b879428466acabaa3fe6f2..747d4bdfe9a6e786718b766c8d6f5a13941d0486 100644 (file)
@@ -1,21 +1,48 @@
-#include "LightApp_DataObject.h"
+// Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
+//
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// 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, or (at your option) any later version.
+//
+// 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
+//
 
-#include "LightApp_Study.h"
-#include "LightApp_RootObject.h"
+// File   : LightApp_DataObject.cxx
+// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
 
-#include "CAM_DataModel.h"
-#include "CAM_Module.h"
+#include "LightApp_DataObject.h"
+#include "LightApp_Study.h"
+#include "LightApp_DataModel.h"
+#include "LightApp_Module.h"
+#include "LightApp_Application.h"
 
-#include <SUIT_Application.h>
-#include <SUIT_ResourceMgr.h>
+#include <CAM_Module.h>
 #include <SUIT_DataObjectKey.h>
 
-#include <qobject.h>
+#include <QVariant>
+
+#include <iostream>
 
 /*!
-       Class: LightApp_DataObject::Key
-       Level: Internal
+  \class LightApp_DataObject::Key
+  \brief Represents unique data object key for the LightApp_DataObject
+  class instances.
+  \internal
 */
+
 class LightApp_DataObject::Key : public SUIT_DataObjectKey
 {
 public:
@@ -29,135 +56,550 @@ private:
   QString myEntry;
 };
 
-/*!Constructor. Initialize by \a entry.*/
+/*!
+  \brief Constructor.
+  \internal
+  \param entry data object entry
+*/
 LightApp_DataObject::Key::Key( const QString& entry )
 : SUIT_DataObjectKey(),
   myEntry( entry )
 {
 }
 
-/*!Destructor. Do nothing.*/
+/*!
+  \brief Destructor.
+  \internal
+*/
 LightApp_DataObject::Key::~Key()
 {
 }
 
-/*!Checks: Is current key less than \a other.*/
+/*!
+  \brief Compares this key with the another one.
+  \internal
+  \param other another data object key
+  \return \c true if this key is less than \a other.
+*/
 bool LightApp_DataObject::Key::isLess( const SUIT_DataObjectKey* other ) const
 {
   Key* that = (Key*)other;
   return myEntry < that->myEntry;
 }
 
-/*!Checks: Is current key equal with \a other.*/
+/*!
+  \brief Compares this key with the another one.
+  \internal
+  \param other another data object key
+  \return \c true if this key is equal to the \a other.
+*/
 bool LightApp_DataObject::Key::isEqual( const SUIT_DataObjectKey* other ) const
 {
   Key* that = (Key*)other;
   return myEntry == that->myEntry;
 }
 
-/*
-       Class: LightApp_DataObject
-       Level: Public
+/*!
+  \class LightApp_DataObject
+  \brief Base data object class to build the data model for all the SALOME modules.
+*/
+
+/*!
+  \brief Constructor.
+  \param parent parent data object
 */
-/*!Constructor. Initialize by \a parent*/
 LightApp_DataObject::LightApp_DataObject( SUIT_DataObject* parent )
-: CAM_DataObject( parent )
+: CAM_DataObject( parent ),
+  myCompDataType( "" ),
+  myCompObject( 0 )
 {
 }
 
-/*!Destructor. Do nothing.*/
+/*!
+  \brief Destructor.
+*/
 LightApp_DataObject::~LightApp_DataObject()
 {
 }
 
-/*!Gets object ID.
- *\retval QString
- */
+int LightApp_DataObject::groupId() const
+{
+  LightApp_DataModel* m = dynamic_cast<LightApp_DataModel*>( dataModel() );
+  return m ? m->groupId() : CAM_DataObject::groupId();
+}
+
+/*!
+  \brief return custom data for data object
+*/
+QVariant LightApp_DataObject::customData(Qtx::CustomDataType type) {
+  switch(type) {
+  case Qtx::IdType:
+    return EntryId;
+    break;
+  default:
+    return QVariant();
+    break;
+  }
+}
+
+/*!
+  \brief Check if the object is visible.
+  \return \c true if this object is displayable or \c false otherwise
+*/
+bool LightApp_DataObject::isVisible() const
+{
+  LightApp_RootObject* r = dynamic_cast<LightApp_RootObject*>( root() );
+  return r && r->study() && componentDataType() != r->study()->getVisualComponentName();
+}
+
+/*!
+  \brief Check if the object is draggable.
+
+  This method can be re-implemented in the subclasses.
+
+  \return \c true if it is possible to drag this object
+*/
+bool LightApp_DataObject::isDraggable() const
+{
+  LightApp_Module* aModule = dynamic_cast<LightApp_Module*>(module());
+  if (aModule) {
+    return aModule->isDraggable(this);
+  }
+  return false;
+}
+
+/*!
+  \brief Check if the drop operation fo this object is possible.
+
+  This method can be re-implemented in the subclasses.
+
+  \param obj object being dropped
+  \return \c true if it is possible to drop an object \c obj
+          to this object
+*/
+bool LightApp_DataObject::isDropAccepted() const
+{
+  LightApp_Module* aModule = dynamic_cast<LightApp_Module*>(module());
+  if (aModule) {
+    return aModule->isDropAccepted(this);
+  }
+  return false;
+}
+
+/*!
+  \brief Check if this object is can't be renamed in place
+
+  This method can be re-implemented in the subclasses.
+  Default implementation returns \c false (all objects can not be renamed).
+
+  \param id column id
+  \return \c true if the item can be renamed by the user in place (e.g. in the Object browser)
+*/
+bool LightApp_DataObject::renameAllowed( const int id ) const
+{
+  if ( id == NameId ) {
+    LightApp_Module* m = dynamic_cast<LightApp_Module*>( module() );
+    LightApp_Application* app = 0;
+    LightApp_RootObject* r = dynamic_cast<LightApp_RootObject*>( root() );
+    if(r && r->study())
+      app  = dynamic_cast<LightApp_Application*>(r->study()->application());
+
+    return ( m && m->renameAllowed( entry() ) ) ||
+      ( app && app->renameAllowed( entry() ) );
+  }
+  return CAM_DataObject::renameAllowed( id );
+}
+
+
+/*!
+  \brief Set name of the this object.
+
+  This method can be re-implemented in the subclasses.
+  Default implementation returns \c false.
+
+  \return \c true if rename operation finished successfully, \c false otherwise.
+*/
+bool LightApp_DataObject::setName(const QString& name)
+{
+    LightApp_Module* m = dynamic_cast<LightApp_Module*>( module() );
+    LightApp_RootObject* r = dynamic_cast<LightApp_RootObject*>( root() );
+    LightApp_Application* app =
+      (r && r->study()) ? dynamic_cast<LightApp_Application*>(r->study()->application()) : 0;
+
+    return ( m && m->renameObject( entry(), name ) ) ||
+           ( app && app->renameObject( entry(), name ) );
+  return CAM_DataObject::setName(name);
+}
+
+
+/*!
+  \brief Get object string identifier.
+
+  This method should be reimplemented in the subclasses.
+  Default implementation returns null string.
+
+  \return object ID
+*/
 QString LightApp_DataObject::entry() const
 {
-  return QString::null;
+  return QString();
+}
+
+/*!
+  \brief Returns the string identifier of the data objects referenced by this one.
+
+  This method should be reimplemented in the subclasses.
+  Default implementation returns null string.
+
+  \return ID string of the referenced data object
+*/
+QString LightApp_DataObject::refEntry() const
+{
+  return QString();
 }
 
-/*!Create and return new key object.*/
+/*!
+  \brief Tells if this data objects is a reference to some other or not.
+
+  The base implementation retuns true, if refEntry() returns non-empty string.
+
+  \return true if refEntry() is a non-empty string.
+*/
+bool LightApp_DataObject::isReference() const
+{
+  return !refEntry().isEmpty();
+}
+
+/*!
+  \brief Get the data object unique key.
+  \return data object key
+*/
 SUIT_DataObjectKey* LightApp_DataObject::key() const
 {
   QString str = entry();
   return new Key( str );
 }
 
-/*!Gets component object.
- *\retval SUIT_DataObject.
- */
-SUIT_DataObject* LightApp_DataObject::componentObject() const
+/*!
+  \brief Get object text data for the specified column.
+
+  Column with \a id == NameId is supposed to be used
+  to get the object name.
+  Column with \a id == EntryId is supposed to be used
+  to get the object entry.
+  Column with \a id == RefEntryId is supposed to be used
+  to show the entry of the object referenced by this one.
+
+  \param id column id
+  \return object text data
+*/
+QString LightApp_DataObject::text( const int id ) const
+{
+  QString txt;
+  
+  switch ( id )
+  {
+  case EntryId:
+    txt = entry();
+    break;
+  case RefEntryId:
+    // Issue 21379: reference support at LightApp level
+    if ( isReference() )
+      txt = refEntry();
+    break;
+  default:
+    // Issue 21379: Note that we cannot return some specially decorated
+    // name string (like "* ref_obj_name") when isReference() returns true, 
+    // since there is no generic way at LightApp level
+    // to query the object name using refEntry() up to now.
+    // TODO: Think how to make reference name generation
+    // more generic at move it here from SalomeApp level...
+    txt = CAM_DataObject::text( id );
+    break;
+  }
+
+  return txt;
+}
+
+/*!
+  \brief Get data object color for the specified column.
+  \param role color role
+  \param id column id (not used)
+  \return object color for the specified column
+*/
+QColor LightApp_DataObject::color( const ColorRole role, const int id) const
 {
-  SUIT_DataObject* compObj = 0; // for root object
+  QColor c;
 
-  if ( parent() && parent() == root() ) 
-    compObj = (SUIT_DataObject*)this; // for component-level objects
-  else 
+  // Issue 21379: reference support at LightApp level
+  // Centralized way for choosing text/background color for references.
+  // Colors for "normal" objects should be chosen by sub-classes.
+  switch ( role )
   {
-    compObj = parent(); // for lower level objects
-    while ( compObj && compObj->parent() != root() )
+  case Text:
+  case Foreground:
+    // text color (not selected item)
+    // TODO: think how to detect invalid references...
+    if ( isReference() )
+      c = QColor( 255, 0, 0 );      // valid reference (red)
+    break;
+
+  case Highlight:
+    // background color for the highlighted item
+    // TODO: think how to detect invalid references...
+    if ( isReference() ) 
+      c = QColor( 255, 0, 0 );      // valid reference (red)
+    break;
+
+  case HighlightedText:
+    // text color for the highlighted item
+    if ( isReference() )
+      c = QColor( 255, 255, 255 );   // white
+    break;
+
+  default:
+    break;
+  }
+
+  if ( !c.isValid() )
+    c = CAM_DataObject::color( role, id );
+
+  return c;
+}
+
+/*!
+  \brief Get the component object.
+  \return component data object
+*/
+SUIT_DataObject* LightApp_DataObject::componentObject() const
+{
+  if ( !myCompObject ) {
+    SUIT_DataObject* compObj = (SUIT_DataObject*)this;
+
+    while ( compObj && compObj->parent() && compObj->parent() != root() ) {
       compObj = compObj->parent();
+    }
+    LightApp_DataObject* that = (LightApp_DataObject*)this;
+    that->myCompObject = compObj;
   }
-  return compObj;
+  return myCompObject;
 }
 
-/*!Get component type.*/
+/*!
+  \brief Get component type.
+  \return component type
+*/
 QString LightApp_DataObject::componentDataType() const
 {
-  SUIT_DataObject* aCompObj = componentObject();
-  LightApp_ModuleObject* anObj = dynamic_cast<LightApp_ModuleObject*>( aCompObj );
-  if ( anObj ) {
-    CAM_DataModel* aModel = anObj->dataModel();
-    if ( aModel )
-      return aModel->module()->name();
+  if ( myCompDataType.isEmpty() ) {
+    SUIT_DataObject* aCompObj = componentObject();
+    CAM_ModuleObject* anObj = dynamic_cast<CAM_ModuleObject*>( aCompObj );
+    if ( anObj ) {
+      CAM_DataModel* aModel = anObj->dataModel();
+      if ( aModel ) {
+        LightApp_DataObject* that = (LightApp_DataObject*)this;
+        that->myCompDataType = aModel->module()->name();
+      }
+    }
   }
-  return "";
+  return myCompDataType;
 }
 
-/*
-       Class: LightApp_ModuleObject
-       Level: Public
+/*!
+  \brief Check if the specified column supports custom sorting.
+  \param id column id
+  \return \c true if column sorting should be customized
+  \sa compare()
+*/
+bool LightApp_DataObject::customSorting( const int id ) const
+{
+  // perform custom sorting for the "Entry" column
+  return id == EntryId ? true : CAM_DataObject::customSorting( id );
+}
+
+/*!
+  \brief Compares data from two items for sorting purposes.
+
+  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 id column id
+  \return result of the comparison
+  \sa customSorting()
+*/
+bool LightApp_DataObject::compare( const QVariant& left, const QVariant& right, const int id ) const
+{
+  if ( id == EntryId )
+  {
+    // perform custom sorting for the "Entry" column
+    QString leftStr  = left.toString();
+    QString rightStr = right.toString();
+    QStringList idsLeft  = leftStr.split( ":", QString::SkipEmptyParts );
+    QStringList idsRight = rightStr.split( ":", QString::SkipEmptyParts );
+    if ( idsLeft.count() > 1 || idsRight.count() > 1 ) {
+      bool result = true;
+      bool calculated = false;
+      for ( int i = 0; i < idsLeft.count() || i < idsRight.count(); i++ ) {
+        bool okLeft = true, okRight = true;
+        int lid = 0, rid = 0;
+        if ( i < idsLeft.count() )
+          lid = idsLeft[i].toInt( &okLeft );
+        if ( i < idsRight.count() )
+          rid = idsRight[i].toInt( &okRight );
+        if ( okLeft && okRight ) {
+          // both seem to be correct integer ID
+         if ( lid < rid ) return true;
+        }
+        else if ( okLeft || okRight ) {
+          // objects with correct (int) ID have higher priority
+          return okLeft;
+        }
+        else {
+          // both not integer ID
+          int r = QString::localeAwareCompare( idsLeft[i], idsRight[i] );
+          if ( !calculated && r != 0 ) {
+            result = r < 0;
+            calculated = true;
+          }
+        }
+      }
+      // we should reach this if the entries are exactly equal
+      return result;
+    }
+    return QString::localeAwareCompare( leftStr, rightStr ) < 0;
+  }
+  return CAM_DataObject::compare( left, right, id );
+}
+
+/*!
+  \class LightApp_ModuleObject
+  \brief Used for optimized access to the data model from the data objects.
+  \sa CAM_ModuleObject class
 */
 
-/*!Constructor.Initialize by \a parent.*/
+/*!
+  \brief Constructor.
+  \param parent parent data object
+*/
 LightApp_ModuleObject::LightApp_ModuleObject( SUIT_DataObject* parent )
-: CAM_RootObject( parent ),
-  CAM_DataObject( parent )
+: CAM_DataObject( parent ),
+  LightApp_DataObject( parent ),
+  CAM_ModuleObject( parent )
 {
 }
 
-/*!Constructor.Initialize by \a module and parent.*/
+/*!
+  \brief Constructor.
+  \param dm data model
+  \param parent parent data object
+*/
 LightApp_ModuleObject::LightApp_ModuleObject( CAM_DataModel* dm, SUIT_DataObject* parent )
-: CAM_RootObject( dm, parent ),
-  CAM_DataObject( parent )
+: CAM_DataObject( parent ),
+  LightApp_DataObject( parent ),
+  CAM_ModuleObject( dm, parent )
 {
 }
 
-/*!Destructor. Do nothing.*/
+/*
+  \brief Destructor.
+*/
 LightApp_ModuleObject::~LightApp_ModuleObject()
 {
 }
 
-/*!Returns module name */
+/*!
+  \brief Get module name.
+  \return module name
+*/
 QString LightApp_ModuleObject::name() const
 {
-  return CAM_RootObject::name();
+  return CAM_ModuleObject::name();
+}
+
+/*!
+  \brief Get data object icon for the specified column.
+  \param id column id
+  \return object icon for the specified column
+*/
+QPixmap LightApp_ModuleObject::icon( const int id ) const
+{
+  return CAM_ModuleObject::icon( id );
 }
 
-/*!Insert new child object to the children list at specified position
- *\add component in Study for this module object if it necessary*/
-void LightApp_ModuleObject::insertChild( SUIT_DataObject* theObj, int thePosition )
+/*!
+  \brief Get data object tooltip for the specified column.
+  \param id column id
+  \return object tooltip for the specified column
+*/
+QString LightApp_ModuleObject::toolTip( const int id ) const
+{
+  return CAM_ModuleObject::toolTip( id );
+}
+
+/*!
+  \brief Insert new child object to the children list at specified position.
+
+  Adds component in the study for this module object if it is not done yet.
+
+  \param obj object to be inserted
+  \param pos position at which data object should be inserted
+*/
+void LightApp_ModuleObject::insertChild( SUIT_DataObject* obj, int pos )
 {
-  CAM_RootObject::insertChild(theObj, thePosition);
+  LightApp_DataObject::insertChild( obj, pos );
 
   CAM_DataModel* aModel = dataModel();
 
-  LightApp_RootObject* aRoot = dynamic_cast<LightApp_RootObject*>(parent());
+  LightApp_RootObject* aRoot = dynamic_cast<LightApp_RootObject*>( parent() );
 
-  if (aRoot)
-    aRoot->study()->addComponent(aModel);
+  if ( aRoot )
+    aRoot->study()->addComponent( aModel );
+}
+
+/*!
+  \class LightApp_RootObject
+  \brief Root data object for the light (without CORBA) SALOME application.
+
+  This class is to be instanciated by only one object - the root object
+  of the LightApp data object tree. This object is not shown in the object browser.
+  The goal of this class is to provide a unified access to LightApp_Study
+  object from LightApp_DataObject instances.
+*/
+
+/*
+  \brief Constructor.
+  \param study study
+*/
+LightApp_RootObject::LightApp_RootObject( LightApp_Study* study )
+: CAM_DataObject( 0 ),
+  LightApp_DataObject( 0 ),
+  myStudy( study )
+{
+}
+
+/*
+  \brief Destructor.
+*/
+LightApp_RootObject::~LightApp_RootObject()
+{
+}
 
+/*
+  \brief Set study.
+  \param study pointer to the study
+*/
+void LightApp_RootObject::setStudy( LightApp_Study* study )
+{
+  myStudy = study;
+}
 
+/*
+  \brief Get study
+  \return pointer to the study
+*/
+LightApp_Study* LightApp_RootObject::study() const
+{
+  return myStudy;
 }