X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FXGUI%2FXGUI_DataModel.cpp;h=16b4997ff20e4d244250620147419016f4d0ee97;hb=77ce6d35ac8d2f0fdaecb4f23e0870bf74e36103;hp=a574c035332be147695d3b3f949daf78e229125a;hpb=9b61e5ee5eafe9d6948d9a78667efa2abec132c3;p=modules%2Fshaper.git diff --git a/src/XGUI/XGUI_DataModel.cpp b/src/XGUI/XGUI_DataModel.cpp index a574c0353..16b4997ff 100644 --- a/src/XGUI/XGUI_DataModel.cpp +++ b/src/XGUI/XGUI_DataModel.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 CEA/DEN, EDF R&D +// Copyright (C) 2014-2024 CEA, EDF // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -12,28 +12,49 @@ // // 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 +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // -// See http://www.salome-platform.org/ or -// email : webmaster.salome@opencascade.com +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // #include "XGUI_DataModel.h" #include "XGUI_ObjectsBrowser.h" +#include "XGUI_Workshop.h" #include #include #include #include +#include +#include #include #include +#include +#include + #include +#ifdef _MSC_VER +#pragma warning(disable: 4100) +#endif +static bool isValidNode(const ModuleBase_ITreeNode* theNode) +{ + ModuleBase_ITreeNode* aParent = 0; + try { + aParent = theNode->parent(); + } + catch (...) { + return false; + } + if (aParent) + return isValidNode(aParent); + return true; +} // Constructor ************************************************* XGUI_DataModel::XGUI_DataModel(QObject* theParent) : QAbstractItemModel(theParent)//, @@ -68,18 +89,31 @@ void XGUI_DataModel::processEvent(const std::shared_ptr& theMess for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) { if ((*aIt)->isInHistory()) aCreated.append(*aIt); + if ((*aIt)->groupName() == ModelAPI_ResultPart::group()) { + emit beforeTreeRebuild(); + myRoot->update(); + rebuildDataTree(); + emit treeRebuilt(); + return; + } } + if (aCreated.length() == 0) + return; + + emit beforeTreeRebuild(); QTreeNodesList aNodes = myRoot->objectCreated(aCreated); ModuleBase_ITreeNode* aParent; int aRow = 0; QModelIndex aParentIndex1, aParentIndex2; ObjectPtr aObj; + bool aRebuildAll = false; + foreach(ModuleBase_ITreeNode* aNode, aNodes) { aObj = aNode->object(); aParent = aNode->parent(); if (aObj.get() && (aObj->groupName() == ModelAPI_Folder::group())) { aParent->update(); - rebuildDataTree(); + aRebuildAll = true; } else { aRow = aParent->nodeRow(aNode); @@ -89,6 +123,10 @@ void XGUI_DataModel::processEvent(const std::shared_ptr& theMess dataChanged(aParentIndex1, aParentIndex2); } } + if (aRebuildAll) + rebuildDataTree(); + + emit treeRebuilt(); } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) { std::shared_ptr aUpdMsg = @@ -97,6 +135,7 @@ void XGUI_DataModel::processEvent(const std::shared_ptr& theMess aUpdMsg->groups(); QTreeNodesList aList; std::list, std::string>>::const_iterator aIt; + emit beforeTreeRebuild(); for (aIt = aMsgGroups.cbegin(); aIt != aMsgGroups.cend(); aIt++) { aList.append(myRoot->objectsDeleted(aIt->first, aIt->second.c_str())); } @@ -112,6 +151,7 @@ void XGUI_DataModel::processEvent(const std::shared_ptr& theMess aNode->parent()->update(); } rebuildDataTree(); + emit treeRebuilt(); } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)) { std::shared_ptr aUpdMsg = @@ -121,6 +161,7 @@ void XGUI_DataModel::processEvent(const std::shared_ptr& theMess QObjectPtrList aCreated; std::set::const_iterator aIt; bool aRebuildAll = false; + emit beforeTreeRebuild(); for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) { ObjectPtr aObj = (*aIt); if (!aObj->isInHistory()) @@ -136,7 +177,6 @@ void XGUI_DataModel::processEvent(const std::shared_ptr& theMess } if (aRebuildAll) { myRoot->update(); - rebuildDataTree(); } else { QSet aParents; @@ -159,8 +199,9 @@ void XGUI_DataModel::processEvent(const std::shared_ptr& theMess foreach(ModuleBase_ITreeNode* aNode, aParents) { aNode->update(); } - rebuildDataTree(); } + rebuildDataTree(); + emit treeRebuilt(); } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_ORDER_UPDATED)) { std::shared_ptr aUpdMsg = @@ -170,16 +211,20 @@ void XGUI_DataModel::processEvent(const std::shared_ptr& theMess std::string aGroup = aUpdMsg->reordered()->group(); ModuleBase_ITreeNode* aNode = myRoot->findParent(aDoc, aGroup.c_str()); if (aNode) { + emit beforeTreeRebuild(); aNode->update(); rebuildDataTree(); + emit treeRebuilt(); } } } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_DOCUMENT_CHANGED)) { - DocumentPtr aDoc = ModelAPI_Session::get()->activeDocument(); - ModuleBase_ITreeNode* aRoot = myRoot->findRoot(aDoc); - if (aRoot) { - updateSubTree(aRoot); + if (ModelAPI_Session::get()->hasModuleDocument()) { + DocumentPtr aDoc = ModelAPI_Session::get()->activeDocument(); + ModuleBase_ITreeNode* aRoot = myRoot->findRoot(aDoc); + if (aRoot) { + updateSubTree(aRoot); + } } } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY)) { @@ -189,13 +234,15 @@ void XGUI_DataModel::processEvent(const std::shared_ptr& theMess QObjectPtrList aCreated; std::set::const_iterator aIt; - bool aRebuildAll = false; for (aIt = aObjects.cbegin(); aIt != aObjects.cend(); aIt++) { ObjectPtr aObj = (*aIt); if (aObj->groupName() == ModelAPI_ResultField::group()) { aCreated.append(aObj); } } + if (aCreated.length() == 0) + return; + emit beforeTreeRebuild(); foreach(ObjectPtr aObj, aCreated) { ModuleBase_ITreeNode* aNode = myRoot->subNode(aObj); if (aNode) { @@ -218,6 +265,7 @@ void XGUI_DataModel::processEvent(const std::shared_ptr& theMess dataChanged(aFirstIdx, aLastIdx); } } + emit treeRebuilt(); } } @@ -233,7 +281,6 @@ void XGUI_DataModel::rebuildDataTree() { beginResetModel(); endResetModel(); - emit treeRebuilt(); } //****************************************************** @@ -334,12 +381,165 @@ bool XGUI_DataModel::removeRows(int theRow, int theCount, const QModelIndex& the Qt::ItemFlags XGUI_DataModel::flags(const QModelIndex& theIndex) const { if (theIndex.isValid()) { - ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer(); - return aNode->flags(theIndex.column()); + ModuleBase_ITreeNode* aNode = static_cast(theIndex.internalPointer()); + // Check that the pointer is Valid + if (!isValidNode(aNode)) + return Qt::NoItemFlags; + Qt::ItemFlags aResultFlags = aNode->flags(theIndex.column()); + // Drag and drop of Part features only if: + // - PartSet is active + // - active Part feature of PartSet is dragged + // - finally if it does not break dependencies between features (but here only drag possibility is checked) + SessionPtr aSession = ModelAPI_Session::get(); + if (aSession->hasModuleDocument() && aSession->moduleDocument() == aSession->activeDocument()) { + + ObjectPtr aNodeObj = aNode->object(); + if (aNodeObj.get() && aNodeObj->groupName() == ModelAPI_Feature::group()) + { + FeaturePtr aNodeFeature = std::dynamic_pointer_cast(aNodeObj); + if (aNodeFeature.get() && aNodeFeature->getKind() == "Part" && !aNodeFeature->isDisabled()) + aResultFlags |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; + } + } + return aResultFlags; + } + return Qt::ItemIsDropEnabled | Qt::ItemFlags(); +} + +bool XGUI_DataModel::canDropMimeData(const QMimeData *theData, Qt::DropAction theAction, + int theRow, int theColumn, const QModelIndex &theParent) const +{ + if (theParent.isValid()) + return false; + ModuleBase_ITreeNode* aSubNode = myRoot->subNode(theRow); + if ((aSubNode && aSubNode->object() && aSubNode->object()->groupName() == ModelAPI_Feature::group()) + || theRow == myRoot->childrenCount()) // into the end of a list of features + { + return true; + } + + return false; // in other cases drop is forbidden +} + +QMimeData* XGUI_DataModel::mimeData(const QModelIndexList& theIndexes) const +{ + std::set aRows; // to avoid duplication of rows and for sorting the indices + foreach (QModelIndex anIndex, theIndexes) { + if (anIndex.isValid() && anIndex.internalPointer()) + aRows.insert(anIndex.row()); } - return Qt::ItemFlags(); + QByteArray anEncodedData; + QDataStream aStream(&anEncodedData, QIODevice::WriteOnly); + for(std::set::iterator aRIter = aRows.begin(); aRIter != aRows.end(); aRIter++) + aStream << *aRIter; + + QMimeData* aMimeData = new QMimeData(); + aMimeData->setData("xgui/moved.rows", anEncodedData); + return aMimeData; } +bool XGUI_DataModel::dropMimeData(const QMimeData *theData, Qt::DropAction theAction, + int theRow, int theColumn, const QModelIndex &theParent) +{ + FeaturePtr aDropAfter; // after this feature it is dropped, NULL if drop the the first place + if (theRow > 0) + { + ModuleBase_ITreeNode* aNode = myRoot->subNode(theRow - 1); + if (aNode && aNode->object() && aNode->object()->groupName() == ModelAPI_Feature::group()) + aDropAfter = std::dynamic_pointer_cast(aNode->object()); + } + SessionPtr aSession = ModelAPI_Session::get(); + if (aDropAfter.get()) // move to the upper enabled feature + { + while (aDropAfter.get() && (aDropAfter->isDisabled() || !aDropAfter->isInHistory())) + aDropAfter = aDropAfter->document()->nextFeature(aDropAfter, true); + } + else { // move after invisible items, not the first (which is coordinate system by default) + std::list allFeatures = aSession->get()->moduleDocument()->allFeatures(); + std::list::iterator aFeature = allFeatures.begin(); + for(; aFeature != allFeatures.end(); aFeature++) + { + if ((*aFeature)->isInHistory()) + break; + aDropAfter = *aFeature; + } + } + // move after the composite feature memebers, if they are invisible (sub elements of sketch) + CompositeFeaturePtr aComposite = std::dynamic_pointer_cast(aDropAfter); + if (aComposite.get()) + { + FeaturePtr aNext = aDropAfter->document()->nextFeature(aDropAfter); + while (aNext.get() && !aNext->isInHistory() && aComposite->isSub(aNext)) { + aDropAfter = aNext; + aNext = aDropAfter->document()->nextFeature(aNext); + } + } + + QByteArray anEncodedData = theData->data("xgui/moved.rows"); + if (anEncodedData.isEmpty()) + return false; // dropped something alien, decline + + QDataStream stream(&anEncodedData, QIODevice::ReadOnly); + std::list aDropped; + while (!stream.atEnd()) { + int aRow; + stream >> aRow; + ModuleBase_ITreeNode* aNode = myRoot->subNode(aRow); + if (aNode) + { + FeaturePtr aFeature = std::dynamic_pointer_cast(aNode->object()); + // feature moved after itself is not moved, add only Part feature, other skip + if (aFeature.get() && aFeature != aDropAfter && aFeature->getKind() == "Part") + aDropped.push_back(aFeature); + } + } + if (aDropped.empty()) // nothing to move + return false; + + // check for the movement is valid due to existing dependencies + std::wstring anErrorStr = ModelAPI_Tools::validateMovement(aDropAfter, aDropped); + if (!anErrorStr.empty()) + { + QMessageBox aMessageBox; + aMessageBox.setWindowTitle(QObject::tr("Move part")); + aMessageBox.setIcon(QMessageBox::Warning); + aMessageBox.setStandardButtons(QMessageBox::Ok); + aMessageBox.setDefaultButton(QMessageBox::Ok); + QString aMessageText(QObject::tr("Part(s) cannot be moved because of breaking dependencies.")); + aMessageBox.setText(aMessageText); + aMessageBox.setDetailedText(QString::fromStdWString(anErrorStr)); + aMessageBox.exec(); + return false; + } + + if (aSession->isOperation()) + { + QMessageBox aMessageBox; + aMessageBox.setWindowTitle(QObject::tr("Move part")); + aMessageBox.setIcon(QMessageBox::Warning); + aMessageBox.setStandardButtons(QMessageBox::Ok); + aMessageBox.setDefaultButton(QMessageBox::Ok); + QString aMessageText(QObject::tr("Cannot move part(s) during another operation.")); + aMessageBox.setText(aMessageText); + aMessageBox.exec(); + return false; + } + + aSession->startOperation("Move Part"); + DocumentPtr aPartSet = aSession->moduleDocument(); + for (std::list::iterator aDrop = aDropped.begin(); aDrop != aDropped.end(); aDrop++) + { + aPartSet->moveFeature(*aDrop, aDropAfter); + aDropAfter = *aDrop; + } + aSession->finishOperation(); + + updateSubTree(myRoot); + myWorkshop->updateHistory(); + + // returns false in any case to avoid calling removeRows after it, + return false; // because number of rows stays the same +} //****************************************************** QModelIndex XGUI_DataModel::documentRootIndex(DocumentPtr theDoc, int theColumn) const @@ -419,3 +619,10 @@ DocumentPtr XGUI_DataModel::document(const QModelIndex& theIndex) const ModuleBase_ITreeNode* aNode = (ModuleBase_ITreeNode*)theIndex.internalPointer(); return aNode->document(); } + + +//****************************************************** +bool XGUI_DataModel::hasNode(ModuleBase_ITreeNode* theNode) const +{ + return myRoot->hasSubNode(theNode); +}