From 94aef9e112998641a9331ff53f2ff56e61f2b540 Mon Sep 17 00:00:00 2001 From: vsv Date: Mon, 27 Jul 2015 15:20:40 +0300 Subject: [PATCH] Second iteration of XML based object browser --- src/Config/Config_DataModelReader.cpp | 36 ++- src/Config/Config_DataModelReader.h | 53 ++++- src/Config/Config_Keywords.h | 5 +- src/Config/dataModel.xml | 10 +- src/ModelAPI/CMakeLists.txt | 1 + src/ModelAPI/ModelAPI_Document.h | 6 +- src/ModelAPI/ModelAPI_Entity.h | 23 ++ src/ModelAPI/ModelAPI_Object.h | 3 +- src/PartSet/PartSet_Module.cpp | 2 + src/XGUI/XGUI_DataModel.cpp | 308 +++++++++++++++++++++----- src/XGUI/XGUI_DataModel.h | 9 + 11 files changed, 392 insertions(+), 64 deletions(-) create mode 100644 src/ModelAPI/ModelAPI_Entity.h diff --git a/src/Config/Config_DataModelReader.cpp b/src/Config/Config_DataModelReader.cpp index f20f9195c..9e55a78d8 100644 --- a/src/Config/Config_DataModelReader.cpp +++ b/src/Config/Config_DataModelReader.cpp @@ -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; } } diff --git a/src/Config/Config_DataModelReader.h b/src/Config/Config_DataModelReader.h index 67455d9a8..d17f54eae 100644 --- a/src/Config/Config_DataModelReader.h +++ b/src/Config/Config_DataModelReader.h @@ -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 myRootFolderNames; std::vector myRootFolderTypes; std::vector myRootFolderIcons; + std::vector myRootFolderShowEmpty; std::string myRootTypes; + + /// Sub document data + std::vector mySubFolderNames; + std::vector mySubFolderTypes; + std::vector mySubFolderIcons; + std::vector mySubFolderShowEmpty; + + bool myIsResultLink; + std::string mySubTypes; }; diff --git a/src/Config/Config_Keywords.h b/src/Config/Config_Keywords.h index 46a7f0137..f16d08ed5 100644 --- a/src/Config/Config_Keywords.h +++ b/src/Config/Config_Keywords.h @@ -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_ */ diff --git a/src/Config/dataModel.xml b/src/Config/dataModel.xml index fae0ff016..b0b80b719 100644 --- a/src/Config/dataModel.xml +++ b/src/Config/dataModel.xml @@ -1,8 +1,14 @@ - + - + + + + + + + \ No newline at end of file diff --git a/src/ModelAPI/CMakeLists.txt b/src/ModelAPI/CMakeLists.txt index 6eef6143c..6036d9e0c 100644 --- a/src/ModelAPI/CMakeLists.txt +++ b/src/ModelAPI/CMakeLists.txt @@ -39,6 +39,7 @@ SET(PROJECT_HEADERS ModelAPI_Tools.h ModelAPI_ShapeValidator.h ModelAPI_Validator.h + ModelAPI_Entity.h ) SET(PROJECT_SOURCES diff --git a/src/ModelAPI/ModelAPI_Document.h b/src/ModelAPI/ModelAPI_Document.h index 719fff08c..9557a0851 100644 --- a/src/ModelAPI/ModelAPI_Document.h +++ b/src/ModelAPI/ModelAPI_Document.h @@ -7,7 +7,9 @@ #ifndef ModelAPI_Document_H_ #define ModelAPI_Document_H_ -#include +#include "ModelAPI.h" +#include "ModelAPI_Entity.h" + #include #include #include @@ -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 index 000000000..49503c3f5 --- /dev/null +++ b/src/ModelAPI/ModelAPI_Entity.h @@ -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 diff --git a/src/ModelAPI/ModelAPI_Object.h b/src/ModelAPI/ModelAPI_Object.h index fd54a5f2d..07776479c 100644 --- a/src/ModelAPI/ModelAPI_Object.h +++ b/src/ModelAPI/ModelAPI_Object.h @@ -9,6 +9,7 @@ #include "ModelAPI.h" #include "ModelAPI_Data.h" +#include "ModelAPI_Entity.h" #include @@ -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 myData; ///< manager of the data model of a feature std::shared_ptr myDoc; ///< document this object belongs to diff --git a/src/PartSet/PartSet_Module.cpp b/src/PartSet/PartSet_Module.cpp index 0d493f7f2..255c6d97f 100644 --- a/src/PartSet/PartSet_Module.cpp +++ b/src/PartSet/PartSet_Module.cpp @@ -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 } } diff --git a/src/XGUI/XGUI_DataModel.cpp b/src/XGUI/XGUI_DataModel.cpp index 935b74ec4..74257d5ff 100644 --- a/src/XGUI/XGUI_DataModel.cpp +++ b/src/XGUI/XGUI_DataModel.cpp @@ -9,6 +9,9 @@ #include #include #include +#include +#include +#include #include @@ -16,12 +19,33 @@ #include +/// Returns ResultPart object if the given object is a Part feature +/// Otherwise returns NULL +ResultPartPtr getPartResult(ModelAPI_Object* theObj) +{ + ModelAPI_Feature* aFeature = dynamic_cast(theObj); + if (aFeature) { + ResultPtr aRes = aFeature->firstResult(); + if (aRes.get() && (aRes->groupName() == ModelAPI_ResultPart::group())) { + return std::dynamic_pointer_cast(aRes); + } + } + return ResultPartPtr(); +} + +ModelAPI_Document* getSubDocument(void* theObj) +{ + ModelAPI_Document* aDoc = dynamic_cast((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& theMess } } } - } + // Deleted object event *********************** + } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) { + std::shared_ptr aUpdMsg = + std::dynamic_pointer_cast(theMessage); + DocumentPtr aDoc = aUpdMsg->document(); + std::set aGroups = aUpdMsg->groups(); + std::set::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(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(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; +} diff --git a/src/XGUI/XGUI_DataModel.h b/src/XGUI/XGUI_DataModel.h index 6d98b9d8e..88a0934b8 100644 --- a/src/XGUI/XGUI_DataModel.h +++ b/src/XGUI/XGUI_DataModel.h @@ -19,6 +19,11 @@ * \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; -- 2.39.2