X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FXGUI%2FXGUI_Workshop.cpp;h=cb56c38795c4e51f8a1c29093dfa6b31a54ee0f2;hb=220bd2b37119be1c65abf88a88792445cb9d99f8;hp=52212d11bff20202126610c9e6f0ffc706be39e7;hpb=bed1e5c3525e9a4d997635c6d3273108c6a52354;p=modules%2Fshaper.git diff --git a/src/XGUI/XGUI_Workshop.cpp b/src/XGUI/XGUI_Workshop.cpp index 52212d11b..cb56c3879 100755 --- a/src/XGUI/XGUI_Workshop.cpp +++ b/src/XGUI/XGUI_Workshop.cpp @@ -66,6 +66,8 @@ #include #include #include +#include +#include #include #include @@ -104,7 +106,11 @@ #include #endif + +QString XGUI_Workshop::MOVE_TO_END_COMMAND = QObject::tr("Move to the end"); + //#define DEBUG_DELETE +//#define DEBUG_FEATURE_NAME XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector) : QObject(), @@ -129,7 +135,7 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector) myDisplayer = new XGUI_Displayer(this); mySelector = new XGUI_SelectionMgr(this); - //connect(mySelector, SIGNAL(selectionChanged()), this, SLOT(updateModuleCommands())); + connect(mySelector, SIGNAL(selectionChanged()), this, SLOT(updateCommandStatus())); myOperationMgr = new XGUI_OperationMgr(this, 0); myActionsMgr = new XGUI_ActionsMgr(this); @@ -160,11 +166,10 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector) SLOT(onOperationCommitted(ModuleBase_Operation*))); connect(myOperationMgr, SIGNAL(operationAborted(ModuleBase_Operation*)), SLOT(onOperationAborted(ModuleBase_Operation*))); - //connect(myOperationMgr, SIGNAL(validationStateChanged(bool)), - // myErrorMgr, SLOT(onValidationStateChanged())); #ifndef HAVE_SALOME connect(myMainWindow, SIGNAL(exitKeySequence()), SLOT(onExit())); + onTrihedronVisibilityChanged(true); #endif connect(this, SIGNAL(errorOccurred(const QString&)), myErrorDlg, SLOT(addError(const QString&))); @@ -215,6 +220,10 @@ void XGUI_Workshop::startApplication() onNew(); + myViewerProxy->connectViewProxy(); + connect(myViewerProxy, SIGNAL(trihedronVisibilityChanged(bool)), + SLOT(onTrihedronVisibilityChanged(bool))); + emit applicationStarted(); } @@ -227,7 +236,7 @@ void XGUI_Workshop::activateModule() connect(myDisplayer, SIGNAL(beforeObjectErase(ObjectPtr, AISObjectPtr)), myModule, SLOT(onBeforeObjectErase(ObjectPtr, AISObjectPtr))); - myActionsMgr->update(); + updateCommandStatus(); // activate visualized objects in the viewer XGUI_Displayer* aDisplayer = displayer(); @@ -235,6 +244,7 @@ void XGUI_Workshop::activateModule() QIntList aModes; module()->activeSelectionModes(aModes); aDisplayer->activateObjects(aModes, aDisplayed); + myOperationMgr->activate(); } void XGUI_Workshop::deactivateModule() @@ -252,6 +262,8 @@ void XGUI_Workshop::deactivateModule() XGUI_Displayer* aDisplayer = displayer(); QObjectPtrList aDisplayed = aDisplayer->displayedObjects(); aDisplayer->deactivateObjects(aDisplayed, true); + + myOperationMgr->deactivate(); } //****************************************************** @@ -280,20 +292,20 @@ void XGUI_Workshop::initMenu() addHistoryMenu(aAction, SIGNAL(updateRedoHistory(const QList&)), SLOT(onRedo(int))); salomeConnector()->addDesktopMenuSeparator("MEN_DESK_EDIT"); - aAction = salomeConnector()->addDesktopCommand("REBUILD_CMD", tr("Rebuild"), tr("Rebuild data objects"), - QIcon(":pictures/rebuild.png"), QKeySequence(), - false, "MEN_DESK_EDIT"); - salomeConnector()->addActionInToolbar( aAction, aToolBarTitle ); + //aAction = salomeConnector()->addDesktopCommand("REBUILD_CMD", tr("Rebuild"), tr("Rebuild data objects"), + // QIcon(":pictures/rebuild.png"), QKeySequence(), + // false, "MEN_DESK_EDIT"); + //salomeConnector()->addActionInToolbar( aAction, aToolBarTitle ); - connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onRebuild())); - salomeConnector()->addDesktopMenuSeparator("MEN_DESK_EDIT"); + //connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onRebuild())); + //salomeConnector()->addDesktopMenuSeparator("MEN_DESK_EDIT"); - aAction = salomeConnector()->addDesktopCommand("SAVEAS_CMD", tr("Export NewGeom..."), tr("Export the current document into a NewGeom file"), + aAction = salomeConnector()->addDesktopCommand("SAVEAS_CMD", tr("Export native..."), tr("Export the current document into a native file"), QIcon(), QKeySequence(), false, "MEN_DESK_FILE"); connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onSaveAs())); - aAction = salomeConnector()->addDesktopCommand("OPEN_CMD", tr("Import NewGeom..."), tr("Import a NewGeom file"), + aAction = salomeConnector()->addDesktopCommand("OPEN_CMD", tr("Import native..."), tr("Import native file"), QIcon(), QKeySequence(), false, "MEN_DESK_FILE"); connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onOpen())); @@ -310,6 +322,10 @@ void XGUI_Workshop::initMenu() aCommand->connectTo(this, SLOT(onSave())); //aCommand->disable(); + aCommand = aGroup->addFeature("SAVEAS_CMD", tr("Save as..."), tr("Save the document into a file"), + QIcon(":pictures/save.png"), QKeySequence()); + aCommand->connectTo(this, SLOT(onSaveAs())); + QString aUndoId = "UNDO_CMD"; aCommand = aGroup->addFeature(aUndoId, tr("Undo"), tr("Undo last command"), QIcon(":pictures/undo.png"), QKeySequence::Undo); @@ -328,13 +344,10 @@ void XGUI_Workshop::initMenu() SIGNAL(updateRedoHistory(const QList&)), SLOT(onRedo(int))); - aCommand = aGroup->addFeature("REBUILD_CMD", tr("Rebuild"), tr("Rebuild data objects"), - QIcon(":pictures/rebuild.png"), QKeySequence()); - aCommand->connectTo(this, SLOT(onRebuild())); + //aCommand = aGroup->addFeature("REBUILD_CMD", tr("Rebuild"), tr("Rebuild data objects"), + // QIcon(":pictures/rebuild.png"), QKeySequence()); + //aCommand->connectTo(this, SLOT(onRebuild())); - aCommand = aGroup->addFeature("SAVEAS_CMD", tr("Save as..."), tr("Save the document into a file"), - QIcon(":pictures/save.png"), QKeySequence()); - aCommand->connectTo(this, SLOT(onSaveAs())); //aCommand->disable(); aCommand = aGroup->addFeature("OPEN_CMD", tr("Open..."), tr("Open a new document"), @@ -386,27 +399,12 @@ void XGUI_Workshop::onAcceptActionClicked() ModuleBase_OperationFeature* aFOperation = dynamic_cast (anOperationMgr->currentOperation()); if (aFOperation) { - if (errorMgr()->canProcessClick(anAction, aFOperation->feature())) - myOperationMgr->onCommitOperation(); + //if (errorMgr()->canProcessClick(anAction, aFOperation->feature())) + myOperationMgr->onCommitOperation(); } } } -//****************************************************** -/*void XGUI_Workshop::onValidationStateChanged(bool theEnabled) -{ - XGUI_OperationMgr* anOperationMgr = operationMgr(); - if (anOperationMgr) { - ModuleBase_OperationFeature* aFOperation = dynamic_cast - (anOperationMgr->currentOperation()); - if (aFOperation) { - QAction* anAction = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Accept); - myErrorMgr->updateActionState(anAction, aFOperation->feature(), theEnabled); - } - } -}*/ - - //****************************************************** void XGUI_Workshop::deactivateActiveObject(const ObjectPtr& theObject, const bool theUpdateViewer) { @@ -486,6 +484,7 @@ void XGUI_Workshop::onOperationResumed(ModuleBase_Operation* theOperation) if (theOperation->getDescription()->hasXmlRepresentation()) { //!< No need for property panel setPropertyPanel(theOperation); + connectToPropertyPanel(true); } updateCommandStatus(); @@ -570,13 +569,15 @@ void XGUI_Workshop::setPropertyPanel(ModuleBase_Operation* theOperation) return; showPropertyPanel(); - QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation(); - ModuleBase_WidgetFactory aFactory(aXmlRepr.toStdString(), myModuleConnector); - myPropertyPanel->cleanContent(); - aFactory.createWidget(myPropertyPanel->contentWidget()); - QList aWidgets = aFactory.getModelWidgets(); + QList aWidgets; + if (!module()->createWidgets(theOperation, aWidgets)) { + QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation(); + ModuleBase_WidgetFactory aFactory(aXmlRepr.toStdString(), myModuleConnector); + aFactory.createWidget(myPropertyPanel->contentWidget()); + aWidgets = aFactory.getModelWidgets(); + } // check compatibility of feature and widgets FeaturePtr aFeature = aFOperation->feature(); @@ -604,7 +605,13 @@ void XGUI_Workshop::setPropertyPanel(ModuleBase_Operation* theOperation) myModule->propertyPanelDefined(theOperation); +#ifndef DEBUG_FEATURE_NAME myPropertyPanel->setWindowTitle(theOperation->getDescription()->description()); +#else + std::string aFeatureName = aFeature->name(); + myPropertyPanel->setWindowTitle(QString("%1: %2").arg(theOperation->getDescription()->description()) + .arg(aFeatureName.c_str())); +#endif myErrorMgr->setPropertyPanel(myPropertyPanel); } @@ -616,11 +623,13 @@ void XGUI_Workshop::connectToPropertyPanel(const bool isToConnect) const QList& aWidgets = aPropertyPanel->modelWidgets(); foreach (ModuleBase_ModelWidget* aWidget, aWidgets) { myModule->connectToPropertyPanel(aWidget, isToConnect); - if (isToConnect) { + if (isToConnect) { connect(aWidget, SIGNAL(valueStateChanged(int)), this, SLOT(onWidgetStateChanged(int))); + connect(aWidget, SIGNAL(valuesChanged()), this, SLOT(onValuesChanged())); } else { disconnect(aWidget, SIGNAL(valueStateChanged(int)), this, SLOT(onWidgetStateChanged(int))); + disconnect(aWidget, SIGNAL(valuesChanged()), this, SLOT(onValuesChanged())); } } } @@ -743,6 +752,14 @@ void XGUI_Workshop::onPreferences() } #endif +//****************************************************** +void XGUI_Workshop::onTrihedronVisibilityChanged(bool theState) +{ + XGUI_Displayer* aDisplayer = displayer(); + if (aDisplayer) + aDisplayer->displayTrihedron(theState); +} + //****************************************************** bool XGUI_Workshop::onSave() { @@ -802,14 +819,18 @@ void XGUI_Workshop::onUndo(int theTimes) { objectBrowser()->treeView()->setCurrentIndex(QModelIndex()); SessionPtr aMgr = ModelAPI_Session::get(); + std::list aUndoList = aMgr->undoList(); if (aMgr->isOperation()) { /// this is important for nested operations /// when sketch operation is active, this condition is false and /// the sketch operation is not aborted operationMgr()->onAbortOperation(); } - for (int i = 0; i < theTimes; ++i) { + std::list::const_iterator aIt = aUndoList.cbegin(); + for (int i = 0; (i < theTimes) && (aIt != aUndoList.cend()); ++i, ++aIt) { aMgr->undo(); + if (QString((*aIt).c_str()) == MOVE_TO_END_COMMAND) + myObjectBrowser->rebuildDataTree(); } operationMgr()->updateApplyOfOperations(); @@ -827,14 +848,18 @@ void XGUI_Workshop::onRedo(int theTimes) objectBrowser()->treeView()->setCurrentIndex(QModelIndex()); SessionPtr aMgr = ModelAPI_Session::get(); + std::list aRedoList = aMgr->redoList(); if (aMgr->isOperation()) { /// this is important for nested operations /// when sketch operation is active, this condition is false and /// the sketch operation is not aborted operationMgr()->onAbortOperation(); } - for (int i = 0; i < theTimes; ++i) { + std::list::const_iterator aIt = aRedoList.cbegin(); + for (int i = 0; (i < theTimes) && (aIt != aRedoList.cend()); ++i, ++aIt) { aMgr->redo(); + if (QString((*aIt).c_str()) == MOVE_TO_END_COMMAND) + myObjectBrowser->rebuildDataTree(); } operationMgr()->updateApplyOfOperations(); updateCommandStatus(); @@ -845,21 +870,21 @@ void XGUI_Workshop::onRedo(int theTimes) } //****************************************************** -void XGUI_Workshop::onRebuild() -{ - SessionPtr aMgr = ModelAPI_Session::get(); - bool aWasOperation = aMgr->isOperation(); // keep this value - if (!aWasOperation) { - aMgr->startOperation("Rebuild"); - } - static const Events_ID aRebuildEvent = Events_Loop::loop()->eventByName("Rebuild"); - Events_Loop::loop()->send(std::shared_ptr( - new Events_Message(aRebuildEvent, this))); - if (!aWasOperation) { - aMgr->finishOperation(); - } - updateCommandStatus(); -} +//void XGUI_Workshop::onRebuild() +//{ +// SessionPtr aMgr = ModelAPI_Session::get(); +// bool aWasOperation = aMgr->isOperation(); // keep this value +// if (!aWasOperation) { +// aMgr->startOperation("Rebuild"); +// } +// static const Events_ID aRebuildEvent = Events_Loop::loop()->eventByName("Rebuild"); +// Events_Loop::loop()->send(std::shared_ptr( +// new Events_Message(aRebuildEvent, this))); +// if (!aWasOperation) { +// aMgr->finishOperation(); +// } +// updateCommandStatus(); +//} //****************************************************** void XGUI_Workshop::onWidgetStateChanged(int thePreviousState) @@ -877,6 +902,27 @@ void XGUI_Workshop::onWidgetStateChanged(int thePreviousState) myModule->widgetStateChanged(thePreviousState); } +//****************************************************** +void XGUI_Workshop::onValuesChanged() +{ + ModuleBase_ModelWidget* aSenderWidget = (ModuleBase_ModelWidget*)(sender()); + if (!aSenderWidget || aSenderWidget->canSetValue()) + return; + + ModuleBase_ModelWidget* anActiveWidget = 0; + ModuleBase_Operation* anOperation = myOperationMgr->currentOperation(); + if (anOperation) { + ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel(); + if (aPanel) + anActiveWidget = aPanel->activeWidget(); + } + if (anActiveWidget) { + ModuleBase_WidgetValidated* aWidgetValidated = dynamic_cast + (anActiveWidget); + aWidgetValidated->clearValidatedCash(); + } +} + ModuleBase_IModule* XGUI_Workshop::loadModule(const QString& theModule) { QString libName = QString::fromStdString(library(theModule.toStdString())); @@ -989,7 +1035,7 @@ void XGUI_Workshop::updateCommandStatus() aCmd->setEnabled(false); } } - myActionsMgr->update(); + myActionsMgr->updateCommandsStatus(); emit commandStatusUpdated(); } @@ -1044,11 +1090,11 @@ void XGUI_Workshop::createDockWidgets() QAction* aCancelAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Abort); connect(aCancelAct, SIGNAL(triggered()), myOperationMgr, SLOT(onAbortOperation())); - connect(myPropertyPanel, SIGNAL(noMoreWidgets()), myModule, SLOT(onNoMoreWidgets())); - connect(myPropertyPanel, SIGNAL(keyReleased(QKeyEvent*)), - myOperationMgr, SLOT(onKeyReleased(QKeyEvent*))); - //connect(myOperationMgr, SIGNAL(validationStateChanged(bool)), - // this, SLOT(onValidationStateChanged(bool))); + connect(myPropertyPanel, SIGNAL(keyReleased(QObject*, QKeyEvent*)), + myOperationMgr, SLOT(onKeyReleased(QObject*, QKeyEvent*))); + + connect(myPropertyPanel, SIGNAL(enterClicked(QObject*)), + myOperationMgr, SLOT(onProcessEnter(QObject*))); } //****************************************************** @@ -1064,8 +1110,8 @@ void XGUI_Workshop::showPropertyPanel() // in order to operation manager could process key events of the panel. // otherwise they are ignored. It happens only if the same(activateWindow) is // not happened by property panel activation(e.g. resume operation of Sketch) - myPropertyPanel->activateWindow(); - myPropertyPanel->setFocus(); + ModuleBase_Tools::activateWindow(myPropertyPanel, "XGUI_Workshop::showPropertyPanel()"); + ModuleBase_Tools::setFocus(myPropertyPanel, "XGUI_Workshop::showPropertyPanel()"); } //****************************************************** @@ -1082,22 +1128,24 @@ void XGUI_Workshop::hidePropertyPanel() // in SALOME mode, workstack made the PyConsole the active window, // set the focus on it. As a result, shortcuts of the application, like // are processed by this console. For example Undo actions. - // It is possible that this code is to be moved to NewGeom package + // It is possible that this code is to be moved to SHAPER package QMainWindow* aDesktop = desktop(); - aDesktop->activateWindow(); - aDesktop->setFocus(); + ModuleBase_Tools::activateWindow(aDesktop, "XGUI_Workshop::hidePropertyPanel()"); + ModuleBase_Tools::setFocus(aDesktop, "XGUI_Workshop::showPropertyPanel()"); } //****************************************************** void XGUI_Workshop::showObjectBrowser() { - myObjectBrowser->parentWidget()->show(); + if (!isSalomeMode()) + myObjectBrowser->parentWidget()->show(); } //****************************************************** void XGUI_Workshop::hideObjectBrowser() { - myObjectBrowser->parentWidget()->hide(); + if (!isSalomeMode()) + myObjectBrowser->parentWidget()->hide(); } //****************************************************** @@ -1118,16 +1166,22 @@ void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked) QObjectPtrList aObjects = mySelector->selection()->selectedObjects(); if (theId == "DELETE_CMD") deleteObjects(); + else if (theId == "CLEAN_HISTORY_CMD") + cleanHistory(); else if (theId == "MOVE_CMD") moveObjects(); else if (theId == "COLOR_CMD") changeColor(aObjects); - else if (theId == "SHOW_CMD") + else if (theId == "SHOW_CMD") { showObjects(aObjects, true); + mySelector->updateSelectionBy(ModuleBase_ISelection::Browser); + } else if (theId == "HIDE_CMD") showObjects(aObjects, false); - else if (theId == "SHOW_ONLY_CMD") + else if (theId == "SHOW_ONLY_CMD") { showOnlyObjects(aObjects); + mySelector->updateSelectionBy(ModuleBase_ISelection::Browser); + } else if (theId == "SHADING_CMD") setDisplayMode(aObjects, XGUI_Displayer::Shading); else if (theId == "WIREFRAME_CMD") @@ -1155,9 +1209,6 @@ void XGUI_Workshop::deleteObjects() QObjectPtrList anObjects = mySelector->selection()->selectedObjects(); if (!abortAllOperations()) return; - // It is necessary to clear selection in order to avoid selection changed event during - // deletion and negative consequences connected with processing of already deleted items - mySelector->clearSelection(); // check whether the object can be deleted. There should not be parts which are not loaded if (!XGUI_Tools::canRemoveOrRename(desktop(), anObjects)) return; @@ -1170,26 +1221,141 @@ void XGUI_Workshop::deleteObjects() if (!(hasFeature || hasParameter)) return; - // 1. start operation - QString aDescription = contextMenuMgr()->action("DELETE_CMD")->text(); - aDescription += tr(" %1"); - QStringList aObjectNames; - foreach (ObjectPtr aObj, anObjects) { - if (!aObj->data()->isValid()) - continue; - aObjectNames << QString::fromStdString(aObj->data()->name()); - } - aDescription = aDescription.arg(aObjectNames.join(", ")); - ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(aDescription, module()); - - operationMgr()->startOperation(anOpAction); // 3. delete objects std::set anIgnoredFeatures; - if (deleteFeatures(anObjects, anIgnoredFeatures, desktop(), true)) { - operationMgr()->commitOperation(); + std::set aDirectRefFeatures, aIndirectRefFeatures; + findReferences(anObjects, aDirectRefFeatures, aIndirectRefFeatures); + + bool doDeleteReferences = true; + if (isDeleteFeatureWithReferences(anObjects, aDirectRefFeatures, aIndirectRefFeatures, + desktop(), doDeleteReferences)) { + // start operation + QString aDescription = contextMenuMgr()->action("DELETE_CMD")->text(); + aDescription += " " + aDescription.arg(XGUI_Tools::unionOfObjectNames(anObjects, ", ")); + ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(aDescription, module()); + operationMgr()->startOperation(anOpAction); + + // It is necessary to clear selection in order to avoid selection changed event during + // deletion and negative consequences connected with processing of already deleted items + mySelector->clearSelection(); + + // delete and commit/abort operation in model + if (deleteFeaturesInternal(anObjects, aDirectRefFeatures, aIndirectRefFeatures, + anIgnoredFeatures, doDeleteReferences)) + operationMgr()->commitOperation(); + else + operationMgr()->abortOperation(operationMgr()->currentOperation()); + } +} + +//************************************************************** +void XGUI_Workshop::cleanHistory() +{ + if (!abortAllOperations()) + return; + + QObjectPtrList anObjects = mySelector->selection()->selectedObjects(); + QObjectPtrList aFeatures; + foreach (ObjectPtr anObject, anObjects) { + FeaturePtr aFeature = std::dynamic_pointer_cast(anObject); + // for parameter result, use the corresponded reature to be removed + if (!aFeature.get() && anObject->groupName() == ModelAPI_ResultParameter::group()) { + aFeature = ModelAPI_Feature::feature(anObject); + } + aFeatures.append(aFeature); + } + + // 1. find all referenced features + QList anUnusedObjects; + std::set aDirectRefFeatures; + //foreach (ObjectPtr anObject, anObjects) { + foreach (ObjectPtr anObject, aFeatures) { + FeaturePtr aFeature = std::dynamic_pointer_cast(anObject); + // for parameter result, use the corresponded reature to be removed + //if (!aFeature.get() && anObject->groupName() == ModelAPI_ResultParameter::group()) { + // aFeature = ModelAPI_Feature::feature(anObject); + //} + if (aFeature.get()) { + std::set alreadyProcessed; + aDirectRefFeatures.clear(); + XGUI_Tools::refsDirectToFeatureInAllDocuments(aFeature, aFeature, aFeatures, + aDirectRefFeatures, alreadyProcessed); + if (aDirectRefFeatures.empty() && !anUnusedObjects.contains(aFeature)) + anUnusedObjects.append(aFeature); + } + } + + // 2. warn about the references remove, break the delete operation if the user chose it + if (!anUnusedObjects.empty()) { + QStringList aNames; + foreach (const ObjectPtr& anObject, anUnusedObjects) { + FeaturePtr aFeature = std::dynamic_pointer_cast(anObject); + aNames.append(aFeature->name().c_str()); + } + QString anUnusedNames = aNames.join(", "); + + QString anActionId = "CLEAN_HISTORY_CMD"; + QString aDescription = contextMenuMgr()->action(anActionId)->text(); + + QMessageBox aMessageBox(desktop()); + aMessageBox.setWindowTitle(aDescription); + aMessageBox.setIcon(QMessageBox::Warning); + aMessageBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes); + aMessageBox.setDefaultButton(QMessageBox::No); + + QString aText = QString(tr("Unused features are the following: %1.\nThese features will be deleted.\nWould you like to continue?") + .arg(anUnusedNames)); + /*QString aText; + if (anUnusedNames.isEmpty()) { + aMessageBox.setStandardButtons(QMessageBox::Ok); + aMessageBox.setDefaultButton(QMessageBox::Ok); + + aText = QString(tr("All features are relevant, there is nothing to be deleted")); + } + else { + aMessageBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes); + aMessageBox.setDefaultButton(QMessageBox::No); + + aText = QString(tr("Unused features are the following: %1.\nThese features will be deleted.\nWould you like to continue?") + .arg(anUnusedNames)); + }*/ + + aMessageBox.setText(aText); + if (aMessageBox.exec() == QMessageBox::No) + return; + + // 1. start operation + aDescription += "by deleting of " + aDescription.arg(XGUI_Tools::unionOfObjectNames(anObjects, ", ")); + ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(aDescription, module()); + operationMgr()->startOperation(anOpAction); + + std::set anIgnoredFeatures; + if (removeFeatures(anUnusedObjects, anIgnoredFeatures, anActionId)) { + operationMgr()->commitOperation(); + } + else { + operationMgr()->abortOperation(operationMgr()->currentOperation()); + } } else { - operationMgr()->abortOperation(operationMgr()->currentOperation()); + QString anActionId = "CLEAN_HISTORY_CMD"; + QString aDescription = contextMenuMgr()->action(anActionId)->text(); + + QMessageBox aMessageBox(desktop()); + aMessageBox.setWindowTitle(aDescription); + aMessageBox.setIcon(QMessageBox::Warning); + aMessageBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes); + aMessageBox.setDefaultButton(QMessageBox::No); + + QString aText; + aMessageBox.setStandardButtons(QMessageBox::Ok); + aMessageBox.setDefaultButton(QMessageBox::Ok); + + aText = QString(tr("All features are relevant, there is nothing to be deleted")); + aMessageBox.setText(aText); + + if (aMessageBox.exec() == QMessageBox::No) + return; } } @@ -1229,72 +1395,87 @@ void XGUI_Workshop::moveObjects() } //************************************************************** -bool XGUI_Workshop::deleteFeatures(const QObjectPtrList& theList, - const std::set& theIgnoredFeatures, - QWidget* theParent, - const bool theAskAboutDeleteReferences) +void XGUI_Workshop::findReferences(const QObjectPtrList& theList, + std::set& aDirectRefFeatures, + std::set& aIndirectRefFeatures) { -#ifdef DEBUG_DELETE - QStringList aDInfo; - QObjectPtrList::const_iterator aDIt = theList.begin(), aDLast = theList.end(); - for (; aDIt != aDLast; ++aDIt) { - aDInfo.append(ModuleBase_Tools::objectInfo((*aDIt))); - } - QString anInfoStr = aDInfo.join(", "); - qDebug(QString("deleteFeatures: %1, %2").arg(theList.size()).arg(anInfoStr).toStdString().c_str()); -#endif - - // 1. find all referenced features - std::set aDirectRefFeatures, aIndirectRefFeatures; foreach (ObjectPtr aDeletedObj, theList) { std::set alreadyProcessed; - XGUI_Tools::refsToFeatureInAllDocuments( - aDeletedObj, aDeletedObj, aDirectRefFeatures, aIndirectRefFeatures, alreadyProcessed); + XGUI_Tools::refsToFeatureInAllDocuments(aDeletedObj, aDeletedObj, theList, aDirectRefFeatures, + aIndirectRefFeatures, alreadyProcessed); std::set aDifference; std::set_difference(aIndirectRefFeatures.begin(), aIndirectRefFeatures.end(), aDirectRefFeatures.begin(), aDirectRefFeatures.end(), std::inserter(aDifference, aDifference.begin())); aIndirectRefFeatures = aDifference; } +} - bool doDeleteReferences = true; +bool XGUI_Workshop::isDeleteFeatureWithReferences(const QObjectPtrList& theList, + const std::set& aDirectRefFeatures, + const std::set& aIndirectRefFeatures, + QWidget* theParent, + bool& doDeleteReferences) +{ + doDeleteReferences = true; - // 2. warn about the references remove, break the delete operation if the user chose it - if (theAskAboutDeleteReferences && !aDirectRefFeatures.empty()) { + QString aDirectNames, aIndirectNames; + if (!aDirectRefFeatures.empty()) { QStringList aDirectRefNames; foreach (const FeaturePtr& aFeature, aDirectRefFeatures) aDirectRefNames.append(aFeature->name().c_str()); - QString aDirectNames = aDirectRefNames.join(", "); + aDirectNames = aDirectRefNames.join(", "); QStringList aIndirectRefNames; foreach (const FeaturePtr& aFeature, aIndirectRefFeatures) aIndirectRefNames.append(aFeature->name().c_str()); - QString aIndirectNames = aIndirectRefNames.join(", "); - - bool canReplaceParameters = true; - foreach (ObjectPtr aObj, theList) { - FeaturePtr aFeature = ModelAPI_Feature::feature(aObj); - if (!std::dynamic_pointer_cast(aFeature->firstResult()).get()) { // the feature is not a parameter - canReplaceParameters = false; - break; - } - } + aIndirectNames = aIndirectRefNames.join(", "); + } - QMessageBox aMessageBox(theParent); - aMessageBox.setWindowTitle(tr("Delete features")); - aMessageBox.setIcon(QMessageBox::Warning); - aMessageBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes); - aMessageBox.setDefaultButton(QMessageBox::No); + bool aCanReplaceParameters = !aDirectRefFeatures.empty(); + QStringList aPartFeatureNames; + foreach (ObjectPtr aObj, theList) { + FeaturePtr aFeature = ModelAPI_Feature::feature(aObj); + // invalid feature data means that the feature is already removed in model, + // we needn't process it. E.g. delete of feature from create operation. The operation abort + // will delete the operation + if (!aFeature->data()->isValid()) + continue; + ResultPtr aFirstResult = aFeature->firstResult(); + std::string aResultGroupName = aFirstResult->groupName(); + if (aResultGroupName == ModelAPI_ResultPart::group()) + aPartFeatureNames.append(aFeature->name().c_str()); - QString aText; - if (canReplaceParameters) { - aText = QString(tr("Selected parameters are used in the following features: %1.\nThese features will be deleted.\n%2Or parameters could be replaced by their values.\nWould you like to continue?")) - .arg(aDirectNames).arg(aIndirectNames.isEmpty() ? QString() : QString(tr("(Also these features will be deleted: %1)\n")).arg(aIndirectNames)); + if (aCanReplaceParameters && aResultGroupName != ModelAPI_ResultParameter::group()) + aCanReplaceParameters = false; + } + QString aPartNames = aPartFeatureNames.join(", "); + + QMessageBox aMessageBox(theParent); + aMessageBox.setWindowTitle(tr("Delete features")); + aMessageBox.setIcon(QMessageBox::Warning); + aMessageBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes); + aMessageBox.setDefaultButton(QMessageBox::No); + + QString aText; + if (!aDirectNames.isEmpty() || !aIndirectNames.isEmpty()) { + if (aCanReplaceParameters) { + aText = QString(tr("Selected parameters are used in the following features: %1.\nThese features will be deleted.\nOr parameters could be replaced by their values.\n") + .arg(aDirectNames)); + if (!aIndirectNames.isEmpty()) + aText += QString(tr("(Also these features will be deleted: %1)\n")).arg(aIndirectNames); QPushButton *aReplaceButton = aMessageBox.addButton(tr("Replace"), QMessageBox::ActionRole); } else { - aText = QString(tr("Selected features are used in the following features: %1.\nThese features will be deleted.\n%2Would you like to continue?")) - .arg(aDirectNames).arg(aIndirectNames.isEmpty() ? QString() : QString(tr("Also these features will be deleted: %1.\n")).arg(aIndirectNames)); + aText = QString(tr("Selected features are used in the following features: %1.\nThese features will be deleted.\n")).arg(aDirectNames); + if (!aIndirectNames.isEmpty()) + aText += QString(tr("(Also these features will be deleted: %1)\n")).arg(aIndirectNames); } + } + if (!aPartNames.isEmpty()) + aText += QString(tr("The following parts will be deleted: %1.\n")).arg(aPartNames); + + if (!aText.isEmpty()) { + aText += "Would you like to continue?"; aMessageBox.setText(aText); aMessageBox.exec(); QMessageBox::ButtonRole aButtonRole = aMessageBox.buttonRole(aMessageBox.clickedButton()); @@ -1308,8 +1489,24 @@ bool XGUI_Workshop::deleteFeatures(const QObjectPtrList& theList, doDeleteReferences = false; } } + return true; +} + +bool XGUI_Workshop::deleteFeatures(const QObjectPtrList& theFeatures, + const std::set& theIgnoredFeatures) +{ + std::set aDirectRefFeatures, aIndirectRefFeatures; + findReferences(theFeatures, aDirectRefFeatures, aIndirectRefFeatures); + return deleteFeaturesInternal(theFeatures, aDirectRefFeatures, aIndirectRefFeatures, + theIgnoredFeatures); +} - // 3. remove referenced features +bool XGUI_Workshop::deleteFeaturesInternal(const QObjectPtrList& theList, + const std::set& aDirectRefFeatures, + const std::set& aIndirectRefFeatures, + const std::set& theIgnoredFeatures, + const bool doDeleteReferences) +{ if (doDeleteReferences) { std::set aFeaturesToDelete = aDirectRefFeatures; aFeaturesToDelete.insert(aIndirectRefFeatures.begin(), aIndirectRefFeatures.end()); @@ -1335,7 +1532,17 @@ bool XGUI_Workshop::deleteFeatures(const QObjectPtrList& theList, } QString anActionId = "DELETE_CMD"; - QString anId = QString::fromStdString(anActionId.toStdString().c_str()); + return removeFeatures(theList, theIgnoredFeatures, anActionId); +} + +//************************************************************** +bool XGUI_Workshop::removeFeatures(const QObjectPtrList& theList, + const std::set& theIgnoredFeatures, + const QString& theActionId) +{ + bool isDone = false; + + QString anId = QString::fromStdString(theActionId.toStdString().c_str()); QStringList anObjectGroups = contextMenuMgr()->actionObjectGroups(anId); // 4. remove the parameter features foreach (ObjectPtr aObj, theList) { @@ -1345,9 +1552,6 @@ bool XGUI_Workshop::deleteFeatures(const QObjectPtrList& theList, if (!anObjectGroups.contains(aGroupName.c_str())) continue; - if (!myModule->canApplyAction(aObj, anActionId)) - continue; - FeaturePtr aFeature = ModelAPI_Feature::feature(aObj); if (aFeature) { /*// TODO: to learn the workshop to delegate the Part object deletion to the PartSet module @@ -1363,6 +1567,7 @@ bool XGUI_Workshop::deleteFeatures(const QObjectPtrList& theList, qDebug(QString("remove feature :%1").arg(anInfoStr).toStdString().c_str()); #endif aDoc->removeFeature(aFeature); + isDone = true; } } } @@ -1773,8 +1978,14 @@ void XGUI_Workshop::synchronizeGroupInViewer(const DocumentPtr& theDoc, int aSize = theDoc->size(theGroup); for (int i = 0; i < aSize; i++) { aObj = theDoc->object(theGroup, i); - if (aObj->isDisplayed()) + if (aObj->isDisplayed()) { + // Hide the presentation with an empty shape. But isDisplayed state of the object should not + // be changed to the object becomes visible when the shape becomes not empty + ResultPtr aRes = std::dynamic_pointer_cast(aObj); + if (aRes.get() && (!aRes->shape().get() || aRes->shape()->isNull())) + continue; myDisplayer->display(aObj, false); + } } if (theUpdateViewer) myDisplayer->updateViewer();