aAction = new QAction(QIcon(":pictures/move.png"), XGUI_Workshop::MOVE_TO_END_COMMAND, this);
addAction("MOVE_CMD", aAction);
+ aAction = new QAction(QIcon(":pictures/delete.png"), tr("Clean history"), this);
+ addAction("CLEAN_HISTORY_CMD", aAction);
+
aAction = new QAction(QIcon(":pictures/color.png"), tr("Color..."), this);
addAction("COLOR_CMD", aAction);
else if (hasFeature && myWorkshop->canMoveFeature())
action("MOVE_CMD")->setEnabled(true);
+ else if (hasFeature)
+ action("CLEAN_HISTORY_CMD")->setEnabled(true);
+
if( aMgr->activeDocument() == aObject->document() )
{
action("RENAME_CMD")->setEnabled(true);
if (hasFeature || hasParameter)
action("DELETE_CMD")->setEnabled(true);
}
+ if (allActive && hasFeature)
+ action("CLEAN_HISTORY_CMD")->setEnabled(true);
}
// Show/Hide command has to be disabled for objects from non active document
aList.clear();
aList.append(action("DELETE_CMD"));
aList.append(action("MOVE_CMD"));
+ aList.append(action("CLEAN_HISTORY_CMD"));
aList.append(mySeparator);
aList.append(action("RENAME_CMD"));
myObjBrowserMenus[ModelAPI_Feature::group()] = aList;
aActions.append(mySeparator);
aActions.append(action("DELETE_CMD"));
//aActions.append(action("MOVE_CMD"));
+ aActions.append(action("CLEAN_HISTORY_CMD"));
aActions.append(action("COLOR_CMD"));
}
theMenu->addActions(aActions);
/// we need to install filter to the application in order to react to 'Delete' key button
/// this key can not be a short cut for a corresponded action because we need to set
/// the actions priority
- qApp->installEventFilter(this);
+ //qApp->installEventFilter(this);
}
XGUI_OperationMgr::~XGUI_OperationMgr()
return res;
}
+//******************************************************************
+QString unionOfObjectNames(const QObjectPtrList& theObjects, const QString& theSeparator)
+{
+ QStringList aObjectNames;
+ foreach (ObjectPtr aObj, theObjects) {
+ if (!aObj->data()->isValid())
+ continue;
+ aObjectNames << QString::fromStdString(aObj->data()->name());
+ }
+ return aObjectNames.join(", ");
+}
+
//******************************************************************
bool isModelObject(FeaturePtr theFeature)
{
//**************************************************************
void refsToFeatureInAllDocuments(const ObjectPtr& theSourceObject, const ObjectPtr& theObject,
+ const QObjectPtrList& theIgnoreList,
std::set<FeaturePtr>& theDirectRefFeatures,
std::set<FeaturePtr>& theIndirectRefFeatures,
std::set<FeaturePtr>& theAlreadyProcessed)
+{
+ refsDirectToFeatureInAllDocuments(theSourceObject, theObject, theIgnoreList, theDirectRefFeatures,
+ theAlreadyProcessed);
+
+ // Run recursion. It is possible recursive dependency, like the following: plane, extrusion uses plane,
+ // axis is built on extrusion. Delete of a plane should check the dependency from the axis also.
+ std::set<FeaturePtr>::const_iterator aFeatureIt = theDirectRefFeatures.begin();
+ for (; aFeatureIt != theDirectRefFeatures.end(); ++aFeatureIt) {
+ std::set<FeaturePtr> aRecursiveRefFeatures;
+ refsToFeatureInAllDocuments(theSourceObject, *aFeatureIt, theIgnoreList,
+ aRecursiveRefFeatures, aRecursiveRefFeatures, theAlreadyProcessed);
+ theIndirectRefFeatures.insert(aRecursiveRefFeatures.begin(), aRecursiveRefFeatures.end());
+ }
+
+}
+
+//**************************************************************
+void refsDirectToFeatureInAllDocuments(const ObjectPtr& theSourceObject, const ObjectPtr& theObject,
+ const QObjectPtrList& theIgnoreList,
+ std::set<FeaturePtr>& theDirectRefFeatures,
+ std::set<FeaturePtr>& theAlreadyProcessed)
{
FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
if (!aFeature.get())
aLast = aRefFeatures.end();
for (; anIt != aLast; anIt++) {
// composite feature should not be deleted when the sub feature is to be deleted
- if (!isSubOfComposite(theSourceObject, *anIt))
+ if (!isSubOfComposite(theSourceObject, *anIt) && !theIgnoreList.contains(*anIt))
theDirectRefFeatures.insert(*anIt);
}
}
}
}
- if (aHasReferenceToObject && !isSubOfComposite(theSourceObject, aFeature))
+ if (aHasReferenceToObject && !isSubOfComposite(theSourceObject, aFeature) &&
+ !theIgnoreList.contains(aFeature))
theDirectRefFeatures.insert(aFeature);
}
}
}
-
- // Run recursion. It is possible recursive dependency, like the following: plane, extrusion uses plane,
- // axis is built on extrusion. Delete of a plane should check the dependency from the axis also.
- std::set<FeaturePtr>::const_iterator aFeatureIt = theDirectRefFeatures.begin();
- for (; aFeatureIt != theDirectRefFeatures.end(); ++aFeatureIt) {
- std::set<FeaturePtr> aRecursiveRefFeatures;
- refsToFeatureInAllDocuments(theSourceObject, *aFeatureIt,
- aRecursiveRefFeatures, aRecursiveRefFeatures, theAlreadyProcessed);
- theIndirectRefFeatures.insert(aRecursiveRefFeatures.begin(), aRecursiveRefFeatures.end());
- }
}
}
// The model concerning tools
+/*! Unite object names in one string using the separator between values
+ \param theObjects a list of objects
+ \param theSeparator a separator
+ */
+QString unionOfObjectNames(const QObjectPtrList& theObjects, const QString& theSeparator);
+
/*!
Returns true if the feature is a model object
\param theFeature a feature
*/
bool XGUI_EXPORT isSubOfComposite(const ObjectPtr& theObject, const FeaturePtr& theFeature);
+/*!
+*/
+void refsDirectToFeatureInAllDocuments(const ObjectPtr& theSourceObject, const ObjectPtr& theObject,
+ const QObjectPtrList& theIgnoreList,
+ std::set<FeaturePtr>& theDirectRefFeatures,
+ std::set<FeaturePtr>& theAlreadyProcessed);
+
/*!
Returns a container of references feature to the source object. The search happens in the object
document and in other Part documents if the object belongs to the PartSet. The search is recursive,
which has the object as a sub object.
\param theSourceObject an object, which references are searched
\param theObject an intermediate recursive object, should be set in the source object
+ \param theIgnoreList an ignore list, the found referernces which coincide with the objects are ignored
\param theDirectRefFeatures direct references
- \param theIndirectRefFeatures indirect references
+ \param theIndirectRefFeatures indirect references. These are features that refers to the direct features
\param theAlreadyProcessed set of processed elements, used for optimization (do not reanalyse processed)
\return a boolean value
*/
void XGUI_EXPORT refsToFeatureInAllDocuments(const ObjectPtr& theSourceObject,
const ObjectPtr& theObject,
+ const QObjectPtrList& theIgnoreList,
std::set<FeaturePtr>& theDirectRefFeatures,
std::set<FeaturePtr>& theIndirectRefFeatures,
std::set<FeaturePtr>& theAlreadyProcessed);
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")
// 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(", "));
+ aDescription += " " + aDescription.arg(XGUI_Tools::unionOfObjectNames(anObjects, ", "));
ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(aDescription, module());
-
operationMgr()->startOperation(anOpAction);
+
// 3. delete objects
std::set<FeaturePtr> anIgnoredFeatures;
if (deleteFeatures(anObjects, anIgnoredFeatures, desktop(), true)) {
}
}
+//**************************************************************
+void XGUI_Workshop::cleanHistory()
+{
+ if (!abortAllOperations())
+ return;
+
+ QObjectPtrList anObjects = mySelector->selection()->selectedObjects();
+
+ // 1. find all referenced features
+ std::set<FeaturePtr> anUnusedFeatures;
+ std::set<FeaturePtr> aDirectRefFeatures;
+ foreach (ObjectPtr anObject, anObjects) {
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);
+ if (aFeature.get()) {
+ std::set<FeaturePtr> alreadyProcessed;
+ aDirectRefFeatures.clear();
+ XGUI_Tools::refsDirectToFeatureInAllDocuments(anObject, anObject, anObjects,
+ aDirectRefFeatures, alreadyProcessed);
+ if (aDirectRefFeatures.empty() && anUnusedFeatures.find(aFeature) == anUnusedFeatures.end())
+ anUnusedFeatures.insert(aFeature);
+ }
+ }
+
+ // 2. warn about the references remove, break the delete operation if the user chose it
+ if (!anUnusedFeatures.empty()) {
+ QStringList aNames;
+ foreach (const FeaturePtr& aFeature, anUnusedFeatures)
+ aNames.append(aFeature->name().c_str());
+ QString anUnusedNames = aNames.join(", ");
+
+ QString anActionId = "CLEAN_HISTORY_CMD";
+ QString aDescription = contextMenuMgr()->action("DELETE_CMD")->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));
+ 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<FeaturePtr> anIgnoredFeatures;
+ if (removeFeatures(anObjects, anIgnoredFeatures, anActionId)) {
+ operationMgr()->commitOperation();
+ }
+ else {
+ operationMgr()->abortOperation(operationMgr()->currentOperation());
+ }
+ }
+}
+
//**************************************************************
void XGUI_Workshop::moveObjects()
{
std::set<FeaturePtr> aDirectRefFeatures, aIndirectRefFeatures;
foreach (ObjectPtr aDeletedObj, theList) {
std::set<FeaturePtr> alreadyProcessed;
- XGUI_Tools::refsToFeatureInAllDocuments(
- aDeletedObj, aDeletedObj, aDirectRefFeatures, aIndirectRefFeatures, alreadyProcessed);
+ XGUI_Tools::refsToFeatureInAllDocuments(aDeletedObj, aDeletedObj, theList, aDirectRefFeatures,
+ aIndirectRefFeatures, alreadyProcessed);
std::set<FeaturePtr> aDifference;
std::set_difference(aIndirectRefFeatures.begin(), aIndirectRefFeatures.end(),
aDirectRefFeatures.begin(), aDirectRefFeatures.end(),
}
QString anActionId = "DELETE_CMD";
- QString anId = QString::fromStdString(anActionId.toStdString().c_str());
+ removeFeatures(theList, theIgnoredFeatures, anActionId);
+}
+
+//**************************************************************
+bool XGUI_Workshop::removeFeatures(const QObjectPtrList& theList,
+ const std::set<FeaturePtr>& 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) {
qDebug(QString("remove feature :%1").arg(anInfoStr).toStdString().c_str());
#endif
aDoc->removeFeature(aFeature);
+ isDone = true;
}
}
}