Salome HOME
Second iteration of XML based object browser
authorvsv <vitaly.smetannikov@opencascade.com>
Mon, 27 Jul 2015 12:20:40 +0000 (15:20 +0300)
committervsv <vitaly.smetannikov@opencascade.com>
Mon, 27 Jul 2015 12:20:53 +0000 (15:20 +0300)
src/Config/Config_DataModelReader.cpp
src/Config/Config_DataModelReader.h
src/Config/Config_Keywords.h
src/Config/dataModel.xml
src/ModelAPI/CMakeLists.txt
src/ModelAPI/ModelAPI_Document.h
src/ModelAPI/ModelAPI_Entity.h [new file with mode: 0644]
src/ModelAPI/ModelAPI_Object.h
src/PartSet/PartSet_Module.cpp
src/XGUI/XGUI_DataModel.cpp
src/XGUI/XGUI_DataModel.h

index f20f9195c2271f59d21af97dd16234978f2201e2..9e55a78d890d01956dbec213c8bf23daf37766c0 100644 (file)
@@ -15,7 +15,7 @@
 
 
 Config_DataModelReader::Config_DataModelReader()
-    : Config_XMLReader(DATAMODEL_FILE)
+    : Config_XMLReader(DATAMODEL_FILE), isRootReading(true), myIsResultLink(false)
 {
 }
 
@@ -31,11 +31,37 @@ void Config_DataModelReader::processNode(xmlNodePtr theNode)
     if (aName.empty() || aGroupType.empty())
       Events_Error::send("Reading dataModel.xml: wrong folder definition");
    
-    myRootFolderNames.push_back(aName);
-    myRootFolderTypes.push_back(aGroupType);
-    myRootFolderIcons.push_back(getProperty(theNode, NODE_ICON));
-  } else if  (isNode(theNode, ROOT_NODE, NULL)) {
+    std::string aIcon = getProperty(theNode, NODE_ICON);
+    std::string aEmpty = getProperty(theNode, SHOW_EMPTY);
+    std::string::iterator aIt;
+    for (aIt = aEmpty.begin(); aIt != aEmpty.end(); aIt++) {
+      (*aIt) = toupper(*aIt);
+    }
+    bool aIsEmpty = (aEmpty == "FALSE")? false : true;
+
+   if (isRootReading) {
+      myRootFolderNames.push_back(aName);
+      myRootFolderTypes.push_back(aGroupType);
+      myRootFolderIcons.push_back(aIcon);
+      myRootFolderShowEmpty.push_back(aIsEmpty);
+   } else {
+      mySubFolderNames.push_back(aName);
+      mySubFolderTypes.push_back(aGroupType);
+      mySubFolderIcons.push_back(aIcon);
+      mySubFolderShowEmpty.push_back(aIsEmpty);
+   }
+  } else if  (isNode(theNode, ROOT_DOCUMENT, NULL)) {
+    isRootReading = true;
     myRootTypes = getProperty(theNode, GROUP_TYPE);
+  } else if  (isNode(theNode, SUB_DOCUMENT, NULL)) {
+    isRootReading = false;
+    mySubTypes = getProperty(theNode, GROUP_TYPE);
+    std::string isResult = getProperty(theNode, LINK_ITEM);
+    std::string::iterator aIt;
+    for (aIt = isResult.begin(); aIt != isResult.end(); aIt++) {
+      (*aIt) = toupper(*aIt);
+    }
+    myIsResultLink = (isResult == "TRUE")? true : false;
   }
 }
 
index 67455d9a8cd982a1a7e1ddff83f7b6c9b1498aee..d17f54eaeef01d6dc12b30890fc57c9af9e38015 100644 (file)
@@ -32,6 +32,7 @@ class Config_DataModelReader : public Config_XMLReader
   CONFIG_EXPORT Config_DataModelReader();
   CONFIG_EXPORT virtual ~Config_DataModelReader();
 
+  // ROOT folders propertiues *****************
   /// Returns name of type of tree items in root
   CONFIG_EXPORT std::string rootType() const { return myRootTypes; }
 
@@ -54,16 +55,66 @@ class Config_DataModelReader : public Config_XMLReader
   /// \param theType type of objects in folder
   CONFIG_EXPORT int rootFolderId(std::string theType) const;
 
- protected:
+  /// Returns true if the folder can be shown without items
+  /// \param theId id of the folder
+  CONFIG_EXPORT bool rootShowEmpty(int theId) const { return myRootFolderShowEmpty[theId]; }
+
+
+
+  // SUB folders propertiues ********************
+  /// Returns name of type of tree items in sub document
+  CONFIG_EXPORT std::string subType() const { return mySubTypes; }
+
+  /// Returns number of folders under sub document 
+  CONFIG_EXPORT int subFoldersNumber() const { return mySubFolderNames.size(); }
+
+  /// Returns name of the folder by its Id
+  /// \param theId id of the folder
+  CONFIG_EXPORT std::string subFolderName(int theId) const { return mySubFolderNames[theId]; }
+
+  /// Returns data type in the folder by its Id
+  /// \param theId id of the folder
+  CONFIG_EXPORT std::string subFolderType(int theId) const { return mySubFolderTypes[theId]; }
+
+  /// Returns icon of a folder by its Id
+  /// \param theId id of the folder
+  CONFIG_EXPORT std::string subFolderIcon(int theId) const { return mySubFolderIcons[theId]; }
+
+  /// Returns true if the folder can be shown without items
+  /// \param theId id of the folder
+  CONFIG_EXPORT bool subShowEmpty(int theId) const { return mySubFolderShowEmpty[theId]; }
+
+  /// Returns id of a folder containing the given type
+  /// \param theType type of objects in folder
+  CONFIG_EXPORT int subFolderId(std::string theType) const;
+
+  /// Returns true if the sub-document data tree has to be attached to Part Result node
+  /// Otherwise it has to be connected to Part feature node
+  CONFIG_EXPORT bool isAttachToResult() const { return myIsResultLink; }
+
+protected:
   /// Overloaded method. Defines how to process each node
   virtual void processNode(xmlNodePtr theNode);
 
 private:
+  bool isRootReading;
+
+  /// Root document data
   std::vector<std::string> myRootFolderNames;
   std::vector<std::string> myRootFolderTypes;
   std::vector<std::string> myRootFolderIcons;
+  std::vector<bool> myRootFolderShowEmpty;
 
   std::string myRootTypes;
+
+  /// Sub document data
+  std::vector<std::string> mySubFolderNames;
+  std::vector<std::string> mySubFolderTypes;
+  std::vector<std::string> mySubFolderIcons;
+  std::vector<bool> mySubFolderShowEmpty;
+
+  bool myIsResultLink;
+  std::string mySubTypes;
 };
 
 
index 46a7f013732d74fa44cea3736cfbc647fb5c2688..f16d08ed57cea9ae83f94654b9a7ac2f2e56d558 100644 (file)
@@ -102,7 +102,10 @@ const static char* DATAMODEL_FILE = "dataModel.xml";
 const static char* NODE_FOLDER = "folder";
 const static char* FOLDER_NAME = "name";
 const static char* GROUP_TYPE = "group_type";
-const static char* ROOT_NODE = "tree_root";
+const static char* ROOT_DOCUMENT = "root_document";
+const static char* SUB_DOCUMENT = "sub_document";
 const static char* NODE_ICON = "icon";
+const static char* SHOW_EMPTY = "show_empty";
+const static char* LINK_ITEM = "from_result";
 
 #endif /* CONFIG_KEYWORDS_H_ */
index fae0ff016c939f74af645273b936247b90574d96..b0b80b7198491af1e80ea1d1ba5b82211bf573ba 100644 (file)
@@ -1,8 +1,14 @@
 <!-- Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
 <data_model>
-    <tree_root group_type="Features">
+    <root_document group_type="Features">
         <folder name="Parameters" group_type="Parameters" icon=":pictures/constr_folder.png"/>
         <folder name="Constructions" group_type="Construction" icon=":pictures/constr_folder.png"/>
         <folder name="Parts" group_type="Parts" icon=":pictures/constr_folder.png"/>
-    </tree_root>
+    </root_document>
+    <sub_document group_type="Features" from_result="false">
+        <folder name="Parameters" group_type="Parameters" icon=":pictures/constr_folder.png"/>
+        <folder name="Constructions" group_type="Construction" icon=":pictures/constr_folder.png"/>
+        <folder name="Bodies" group_type="Bodies" icon=":pictures/constr_folder.png"/>
+        <folder name="Groups" group_type="Groups" icon=":pictures/constr_folder.png" show_empty="false"/>
+    </sub_document>
 </data_model>
\ No newline at end of file
index 6eef6143c5e687a0f53f2187ecae81c07d95d625..6036d9e0c4eafc4b35f1cdb82ac71c76cdf9d43f 100644 (file)
@@ -39,6 +39,7 @@ SET(PROJECT_HEADERS
     ModelAPI_Tools.h
     ModelAPI_ShapeValidator.h
     ModelAPI_Validator.h
+       ModelAPI_Entity.h
 )
 
 SET(PROJECT_SOURCES
index 719fff08ceafab1c362e26c8ebb28d7ce7dd25ec..9557a0851235e1552d27c5cebf82efa864e2cd3e 100644 (file)
@@ -7,7 +7,9 @@
 #ifndef ModelAPI_Document_H_
 #define ModelAPI_Document_H_
 
-#include <ModelAPI.h>
+#include "ModelAPI.h"
+#include "ModelAPI_Entity.h"
+
 #include <string>
 #include <memory>
 #include <vector>
@@ -31,7 +33,7 @@ class ModelAPI_Data;
  * Document contains all data that must be stored/retrived in the file.
  * Also it provides acces to this data: open/save, transactions management etc.
  */
-class ModelAPI_Document
+class ModelAPI_Document: public ModelAPI_Entity
 {
 public:
   //! Returns the kind of the document: "PartSet", "Part", or something else.
diff --git a/src/ModelAPI/ModelAPI_Entity.h b/src/ModelAPI/ModelAPI_Entity.h
new file mode 100644 (file)
index 0000000..49503c3
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File:        ModelAPI_Entity.h
+// Created:     27 July 2015
+// Author:      Vitaly SMETANNIKOV
+
+#ifndef ModelAPI_Entity_H_
+#define ModelAPI_Entity_H_
+
+/**\class ModelAPI_Entity
+ * \ingroup DataModel
+ * \brief Represents a common parent class for Objects and documents.
+ * Provided in order to make possible distingiushing of objects and documents
+ * by downcasting of their pointers.
+ */
+class ModelAPI_Entity
+{
+public:
+  /// Empty function which is added for virtualisation of the interface
+  virtual void emptyFunction() const {}
+};
+
+#endif
\ No newline at end of file
index fd54a5f2d9f8215ccc95e334a39260c404532011..07776479cf194c85bbae1d5bd82807fab11315b1 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "ModelAPI.h"
 #include "ModelAPI_Data.h"
+#include "ModelAPI_Entity.h"
 
 #include <memory>
 
@@ -24,7 +25,7 @@ class ModelAPI_Document;
  * objects related to the features and their results. Contains attributes of this 
  * object in the "Data".
  */
-class ModelAPI_Object
+class ModelAPI_Object: public ModelAPI_Entity
 {
   std::shared_ptr<ModelAPI_Data> myData;  ///< manager of the data model of a feature
   std::shared_ptr<ModelAPI_Document> myDoc;  ///< document this object belongs to
index 0d493f7f20f36032d55c98f80cd3e94b0263da21..255c6d97f78805d15a50399f723b732b0f180c8e 100644 (file)
@@ -761,12 +761,14 @@ void PartSet_Module::customizeObjectBrowser(QWidget* theObjectBrowser)
     aPalet.setColor(QPalette::Text, QColor(0, 72, 140));
     aLabel->setPalette(aPalet);
     aOB->treeView()->setExpandsOnDoubleClick(false);
+#ifdef ModuleDataModel
     connect(aOB->treeView(), SIGNAL(doubleClicked(const QModelIndex&)), 
       SLOT(onTreeViewDoubleClick(const QModelIndex&)));
     connect(aOB, SIGNAL(headerMouseDblClicked(const QModelIndex&)), 
       SLOT(onTreeViewDoubleClick(const QModelIndex&)));
     connect(aOB->treeView(), SIGNAL(doubleClicked(const QModelIndex&)), 
       myDataModel, SLOT(onMouseDoubleClick(const QModelIndex&)));
+#endif
   }
 }
 
index 935b74ec40a6094d91a30da94a27e69cfdb86cbd..74257d5ff8c4c9dc114371e0b7bf9ae249bfb2d0 100644 (file)
@@ -9,6 +9,9 @@
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Document.h>
 #include <ModelAPI_Events.h>
+#include <ModelAPI_ResultParameter.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_ResultPart.h>
 
 #include <Config_FeatureMessage.h>
 
 
 #include <QIcon>
 
+/// Returns ResultPart object if the given object is a Part feature
+/// Otherwise returns NULL
+ResultPartPtr getPartResult(ModelAPI_Object* theObj)
+{
+  ModelAPI_Feature* aFeature = dynamic_cast<ModelAPI_Feature*>(theObj);
+  if (aFeature) {
+    ResultPtr aRes = aFeature->firstResult();
+    if (aRes.get() && (aRes->groupName() == ModelAPI_ResultPart::group())) {
+      return std::dynamic_pointer_cast<ModelAPI_ResultPart>(aRes);
+    }
+  }
+  return ResultPartPtr();
+}
+
+ModelAPI_Document* getSubDocument(void* theObj)
+{
+  ModelAPI_Document* aDoc = dynamic_cast<ModelAPI_Document*>((ModelAPI_Entity*)theObj);
+  return aDoc;
+}
+
+
+// Constructor *************************************************
 XGUI_DataModel::XGUI_DataModel(QObject* theParent) : QAbstractItemModel(theParent)
 {
   myXMLReader.readAll();
 
   Events_Loop* aLoop = Events_Loop::loop();
-  aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
   aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
   aLoop->registerListener(this, Events_Loop::eventByName(Config_FeatureMessage::GUI_EVENT()));
@@ -60,7 +84,29 @@ void XGUI_DataModel::processEvent(const std::shared_ptr<Events_Message>& theMess
         }
       }
     }
-  }
+    // Deleted object event ***********************
+  } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
+    std::shared_ptr<ModelAPI_ObjectDeletedMessage> aUpdMsg =
+        std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
+    DocumentPtr aDoc = aUpdMsg->document();
+    std::set<std::string> aGroups = aUpdMsg->groups();
+    std::set<std::string>::const_iterator aIt;
+    for (aIt = aGroups.begin(); aIt != aGroups.end(); ++aIt) {
+      std::string aGroup = (*aIt);
+      if (aDoc == aRootDoc) {  // If root objects
+        int aRow = aRootDoc->size(aGroup);
+        if (aGroup == aRootType) {
+          removeRow(aRow + aNbFolders);
+        } else {
+          int aFolderId = myXMLReader.rootFolderId(aGroup);
+          if (aFolderId != -1) {
+            QModelIndex aFolderIndex = createIndex(aFolderId, 0, -1);
+            removeRow(aRow, aFolderIndex);
+          }
+        }
+      }
+    }
+  } 
 }
 
 //******************************************************
@@ -78,18 +124,42 @@ void XGUI_DataModel::rebuildDataTree()
 //******************************************************
 ObjectPtr XGUI_DataModel::object(const QModelIndex& theIndex) const
 {
+  if (theIndex.internalId() < 0) // this is a folder
+    return ObjectPtr();
+  ModelAPI_Object* aObj = (ModelAPI_Object*)theIndex.internalPointer();
+  // We can not create the ObjectPtr directly because the pointer will be deleted 
+  // with deletion of the ObjectPtr because its counter become to 0.
+  DocumentPtr aDoc = aObj->document();
+  std::string aType = aObj->groupName();
+
+  ObjectPtr aObjPtr;
+  for (int i = 0; i < aDoc->size(aType); i++) {
+    aObjPtr = aDoc->object(aType, i);
+    if (aObjPtr.get() == aObj)
+      return aObjPtr;
+  }
   return ObjectPtr();
 }
 
 //******************************************************
 QModelIndex XGUI_DataModel::objectIndex(const ObjectPtr theObject) const
 {
-  //std::string aType = theObject->groupName();
-  //DocumentPtr aDoc = theObject->document();
-  //int aRow = aDoc->index(theObject);
-  //if (aRow == -1)
+  std::string aType = theObject->groupName();
+  DocumentPtr aDoc = theObject->document();
+  int aRow = aDoc->index(theObject);
+  if (aRow == -1)
     return QModelIndex();
-  //return createIndex(aRow, 0, theObject.get());
+
+  SessionPtr aSession = ModelAPI_Session::get();
+  DocumentPtr aRootDoc = aSession->moduleDocument();
+  if (aDoc == aRootDoc && myXMLReader.rootType() == aType) { 
+    // The object from root document
+    aRow += myXMLReader.rootFoldersNumber();
+  } else if (myXMLReader.subType() == aType) { 
+    // The object from sub document
+    aRow += myXMLReader.subFoldersNumber();
+  }
+  return createIndex(aRow, 0, theObject.get());
 }
 
 //******************************************************
@@ -109,32 +179,37 @@ QVariant XGUI_DataModel::data(const QModelIndex& theIndex, int theRole) const
     return QVariant();
   }
 
-  int aParentRow = theIndex.internalId();
-  if (aParentRow == -1) { // First level of items
-    if (theIndexRow < aNbFolders) { // A folder
+  int aParentId = theIndex.internalId();
+  if (aParentId == -1) { // root folders
+    switch (theRole) {
+      case Qt::DisplayRole:
+        return QString(myXMLReader.rootFolderName(theIndexRow).c_str()) + 
+          QString(" (%1)").arg(rowCount(theIndex));
+      case Qt::DecorationRole:
+        return QIcon(myXMLReader.rootFolderIcon(theIndexRow).c_str());
+    }
+  } else {
+    ModelAPI_Document* aSubDoc = getSubDocument(theIndex.internalPointer());
+    if (aSubDoc) { // this is a folder of sub document
       switch (theRole) {
         case Qt::DisplayRole:
-          return QString(myXMLReader.rootFolderName(theIndexRow).c_str()) + 
+          return QString(myXMLReader.subFolderName(theIndexRow).c_str()) + 
             QString(" (%1)").arg(rowCount(theIndex));
         case Qt::DecorationRole:
-          return QIcon(myXMLReader.rootFolderIcon(theIndexRow).c_str());
+          return QIcon(myXMLReader.subFolderIcon(theIndexRow).c_str());
       }
     } else {
-      ObjectPtr aObj = aRootDoc->object(myXMLReader.rootType(), theIndexRow - aNbFolders);
-      switch (theRole) {
-        case Qt::DisplayRole:
-          return aObj->data()->name().c_str();
-        //case Qt::DecorationRole:
-        //  return featureIcon(aFeature);
-      }
-    }
-  } else { // Content of folders
-    if (aParentRow < aNbFolders) {
-      std::string aType = myXMLReader.rootFolderType(aParentRow);
-      ObjectPtr aObj = aRootDoc->object(aType, theIndexRow);
+      ModelAPI_Object* aObj = (ModelAPI_Object*)theIndex.internalPointer();
       switch (theRole) {
-        case Qt::DisplayRole:
-          return aObj->data()->name().c_str();
+      case Qt::DisplayRole:
+        if (aObj->groupName() == ModelAPI_ResultParameter::group()) {
+          ModelAPI_ResultParameter* aParam = dynamic_cast<ModelAPI_ResultParameter*>(aObj);
+          AttributeDoublePtr aValueAttribute = aParam->data()->real(ModelAPI_ResultParameter::VALUE());
+          QString aVal = QString::number(aValueAttribute->value());
+          QString aTitle = QString(aObj->data()->name().c_str());
+          return aTitle + " = " + aVal;
+        }
+        return aObj->data()->name().c_str();
       }
     }
   }
@@ -154,21 +229,40 @@ int XGUI_DataModel::rowCount(const QModelIndex& theParent) const
   if (!aSession->hasModuleDocument())
     return 0;
   DocumentPtr aRootDoc = aSession->moduleDocument();
-  int aNbFolders = myXMLReader.rootFoldersNumber();
 
-  int aNbItems = 0;
-  std::string aType = myXMLReader.rootType();
-  if (!aType.empty())
-    aNbItems = aRootDoc->size(aType);
-
-  if (!theParent.isValid())
+  if (!theParent.isValid()) {
+    // Return number of items in root
+    int aNbFolders = myXMLReader.rootFoldersNumber();
+    int aNbItems = 0;
+    std::string aType = myXMLReader.rootType();
+    if (!aType.empty())
+      aNbItems = aRootDoc->size(aType);
     return aNbFolders + aNbItems;
+  }
 
-  int aParentPos = theParent.row();
-  if (aParentPos < aNbFolders) {
-    // This is number of items under folder
-    aType = myXMLReader.rootFolderType(aParentPos);
-    return aRootDoc->size(aType);
+  int aId = theParent.internalId();
+  if (aId < 0) { 
+    // this is a folder
+    int aParentPos = theParent.row();
+    if (aId == -1) { // first level of folders
+      std::string aType = myXMLReader.rootFolderType(aParentPos);
+      return aRootDoc->size(aType);
+    }
+  } else {
+    // It is an object which could have children
+    ModelAPI_Object* aObj = (ModelAPI_Object*)theParent.internalPointer();
+
+    // Check for Part feature
+    ResultPartPtr aPartRes = getPartResult(aObj);
+    if (aPartRes.get()) {
+      DocumentPtr aSubDoc = aPartRes->partDoc();
+      int aNbSubFolders = myXMLReader.subFoldersNumber();
+      int aNbSubItems = 0;
+      std::string aSubType = myXMLReader.subType();
+      if (!aSubType.empty())
+        aNbSubItems = aSubDoc->size(aSubType);
+      return aNbSubItems + aNbSubFolders;
+    }
   }
   return 0;
 }
@@ -182,18 +276,105 @@ int XGUI_DataModel::columnCount(const QModelIndex& theParent) const
 //******************************************************
 QModelIndex XGUI_DataModel::index(int theRow, int theColumn, const QModelIndex &theParent) const
 {
-  if (!theParent.isValid())
-    return createIndex(theRow, theColumn, -1);
+  SessionPtr aSession = ModelAPI_Session::get();
+  DocumentPtr aRootDoc = aSession->moduleDocument();
+  int aNbFolders = myXMLReader.rootFoldersNumber();
 
-  return createIndex(theRow, theColumn, theParent.row());
+  if (!theParent.isValid()) {
+    if (theRow < aNbFolders) // Return first level folder index
+      return createIndex(theRow, theColumn, -1);
+    else { // return object under root index
+      std::string aType = myXMLReader.rootType();
+      int aObjId = theRow - aNbFolders;
+      if (aObjId < aRootDoc->size(aType)) {
+        ObjectPtr aObj = aRootDoc->object(aType, aObjId);
+        QModelIndex aIndex = objectIndex(aObj);
+        if (theColumn != 0)
+          return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
+        return aIndex;
+      }
+      return QModelIndex();
+    }
+  }
+  int aId = theParent.internalId();
+  if (aId == -1) { // return object index inside of first level of folders
+    int aParentPos = theParent.row();
+    std::string aType = myXMLReader.rootFolderType(aParentPos);
+    if (theRow < aRootDoc->size(aType)) {
+      ObjectPtr aObj = aRootDoc->object(aType, theRow);
+      QModelIndex aIndex = objectIndex(aObj);
+      if (theColumn != 0)
+        return createIndex(aIndex.row(), theColumn, aIndex.internalPointer());
+      return aIndex;
+    }
+  } else {
+    // It is an object which could have children
+    ModelAPI_Object* aParentObj = (ModelAPI_Object*)theParent.internalPointer();
+
+    // Check for Part feature
+    ResultPartPtr aPartRes = getPartResult(aParentObj);
+    if (aPartRes.get()) {
+      DocumentPtr aSubDoc = aPartRes->partDoc();
+      int aNbSubFolders = myXMLReader.subFoldersNumber();
+      if (theRow < aNbSubFolders) { // Create a Folder of sub-document
+        return createIndex(theRow, theColumn, aSubDoc.get());
+      }
+    }
+  }
+  return QModelIndex();
 }
 
 //******************************************************
 QModelIndex XGUI_DataModel::parent(const QModelIndex& theIndex) const
 {
-  if (theIndex.isValid() && (theIndex.internalId() != -1)) {
-    return createIndex(theIndex.internalId(), theIndex.column(), -1);
-  }
+  int aId = theIndex.internalId();
+  if (aId != -1) { // The object is not a root folder
+    ModelAPI_Document* aDoc = getSubDocument(theIndex.internalPointer());
+    if (aDoc) { 
+      // It is a folder of sub-document
+      SessionPtr aSession = ModelAPI_Session::get();
+      DocumentPtr aRootDoc = aSession->moduleDocument();
+      if (myXMLReader.isAttachToResult()) { // If document is attached to result
+        int aNb = aRootDoc->size(ModelAPI_ResultPart::group());
+        ObjectPtr aObj;
+        ResultPartPtr aPartRes;
+        for (int i = 0; i < aNb; i++) {
+          aObj = aRootDoc->object(ModelAPI_ResultPart::group(), i);
+          aPartRes = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObj);
+          if (aPartRes.get() && (aPartRes->partDoc().get() == aDoc)) {
+            int aRow = i;
+            if (myXMLReader.rootType() == ModelAPI_Feature::group())
+              aRow += myXMLReader.rootFoldersNumber();
+            return createIndex(aRow, 0, aObj.get());
+          }
+        }
+      } else { // If document is attached to feature
+        int aNb = aRootDoc->size(ModelAPI_Feature::group());
+        ObjectPtr aObj;
+        ResultPartPtr aPartRes;
+        for (int i = 0; i < aNb; i++) {
+          aObj = aRootDoc->object(ModelAPI_Feature::group(), i);
+          aPartRes = getPartResult(aObj.get());
+          if (aPartRes.get() && (aPartRes->partDoc().get() == aDoc)) {
+            int aRow = i;
+            if (myXMLReader.rootType() == ModelAPI_Feature::group())
+              aRow += myXMLReader.rootFoldersNumber();
+            return createIndex(aRow, 0, aObj.get());
+          }
+        }
+      }
+    }
+    ModelAPI_Object* aObj = (ModelAPI_Object*) theIndex.internalPointer();
+    std::string aType = aObj->groupName();
+    if (aType == myXMLReader.rootType())
+      return QModelIndex();
+    else {
+      // return first level of folder index
+      int aFolderId = myXMLReader.rootFolderId(aType);
+      // Items in a one row must have the same parent
+      return createIndex(aFolderId, 0, -1);
+    }
+  } 
   return QModelIndex();
 }
 
@@ -204,13 +385,26 @@ bool XGUI_DataModel::hasChildren(const QModelIndex& theParent) const
   if (!theParent.isValid() && aNbFolders)
     return true;
   if (theParent.internalId() == -1) {
-    if (theParent.row() < aNbFolders) {
-      std::string aType = myXMLReader.rootFolderType(theParent.row());
-      if (!aType.empty()) {
-        SessionPtr aSession = ModelAPI_Session::get();
-        DocumentPtr aRootDoc = aSession->moduleDocument();
-        return aRootDoc->size(aType) > 0;
-      }
+    std::string aType = myXMLReader.rootFolderType(theParent.row());
+    if (!aType.empty()) {
+      SessionPtr aSession = ModelAPI_Session::get();
+      DocumentPtr aRootDoc = aSession->moduleDocument();
+      return aRootDoc->size(aType) > 0;
+    }
+  } else {
+    ModelAPI_Document* aDoc = getSubDocument(theParent.internalPointer());
+    if (aDoc) { 
+      // a folder of sub-document
+      std::string aType = myXMLReader.subFolderType(theParent.row());
+      return aDoc->size(aType) > 0;
+    } else {
+      // Check that it could be an object with children
+      ModelAPI_Object* aObj = (ModelAPI_Object*)theParent.internalPointer();
+
+      // Check for Part feature
+      ResultPartPtr aPartRes = getPartResult(aObj);
+      if (aPartRes.get())
+        return true;
     }
   }
   return false;
@@ -231,4 +425,14 @@ bool XGUI_DataModel::removeRows(int theRow, int theCount, const QModelIndex& the
   beginRemoveRows(theParent, theRow, theRow + theCount - 1);
   endRemoveRows();
   return true;
-}
\ No newline at end of file
+}
+
+//******************************************************
+Qt::ItemFlags XGUI_DataModel::flags(const QModelIndex& theIndex) const
+{
+  Qt::ItemFlags aFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+  if (theIndex.internalId() > -1) {
+    aFlags |= Qt::ItemIsEditable;
+  }
+  return aFlags;
+}
index 6d98b9d8ed46e0f4ac343c9f5bc8ba969444b7bb..88a0934b88f7a3ca5c6bb382a65bc382a73d2227 100644 (file)
  * \ingroup GUI
  * \brief This is a data model for Object Browser (QTreeView).
  * It uses XML file for definition of data tree.
+ * Some tips about organization of the model:
+ * - Non Valid Index - root index
+ * - An index with internal Id == -1 is a folder of root document
+ * - An index which contains internal pointer as ModelAPI_Object its the object
+ * - An index which contains internal pointer as ModelAPI_Document is a folder which belongs to this document
  */
 class XGUI_EXPORT XGUI_DataModel : public QAbstractItemModel, public Events_Listener
 {
@@ -96,6 +101,10 @@ public:
   /// \param theParent a parent model index
   virtual bool removeRows(int theRow, int theCount, const QModelIndex& theParent = QModelIndex());
 
+  /// Returns the item flags for the given index.
+  /// \param theIndex a model index
+  virtual Qt::ItemFlags flags(const QModelIndex& theIndex) const;
+
 
 private:
   Config_DataModelReader myXMLReader;