+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<ModelAPI_Feature>(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<FeaturePtr> allFeatures = aSession->get()->moduleDocument()->allFeatures();
+ std::list<FeaturePtr>::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<ModelAPI_CompositeFeature>(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<FeaturePtr> aDropped;
+ while (!stream.atEnd()) {
+ int aRow;
+ stream >> aRow;
+ ModuleBase_ITreeNode* aNode = myRoot->subNode(aRow);
+ if (aNode)
+ {
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(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<FeaturePtr>::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
+}