diff --git a/src/Gui/Selection/Selection.cpp b/src/Gui/Selection/Selection.cpp index 30a167f691..e09c5c4820 100644 --- a/src/Gui/Selection/Selection.cpp +++ b/src/Gui/Selection/Selection.cpp @@ -62,6 +62,7 @@ using namespace Gui; using namespace std; namespace sp = std::placeholders; +// TODO-theo-vt remove! SelectionGateFilterExternal::SelectionGateFilterExternal(const char* docName, const char* objName) { if (docName) { @@ -104,10 +105,6 @@ SelectionObserver::SelectionObserver(const ViewProviderDocumentObject* vp, bool : resolve(resolve) , blockedSelection(false) { - if (vp && vp->getObject() && vp->getObject()->getDocument()) { - filterDocName = vp->getObject()->getDocument()->getName(); - filterObjName = vp->getObject()->getNameInDocument(); - } if (attach) { attachSelection(); } @@ -149,12 +146,6 @@ void SelectionObserver::attachSelection() std::bind(&SelectionObserver::_onSelectionChanged, this, sp::_1) ); // NOLINTEND - - if (!filterDocName.empty()) { - Selection().addSelectionGate( - new SelectionGateFilterExternal(filterDocName.c_str(), filterObjName.c_str()) - ); - } } } @@ -182,9 +173,6 @@ void SelectionObserver::detachSelection() { if (connectSelection.connected()) { connectSelection.disconnect(); - if (!filterDocName.empty()) { - Selection().rmvSelectionGate(); - } } } @@ -827,24 +815,29 @@ int SelectionSingleton::setPreselect( ) { if (!pDocName || !pObjectName) { - rmvPreselect(); + rmvPreselect(); // Invalid request return 0; } + if (!pSubName) { pSubName = ""; } if (DocName == pDocName && FeatName == pObjectName && SubName == pSubName) { - return -1; + return -1; // Already pre-selected } rmvPreselect(); - if (ActiveGate && signal != SelectionChanges::MsgSource::Internal) { - App::Document* pDoc = getDocument(pDocName); - if (!pDoc || !pObjectName) { - return 0; - } + App::Document* pDoc = getDocument(pDocName); + if (!pDoc) { + return 0; // Invalid request + } + auto foundGate = docSelectionGate.find(pDoc); + + if (foundGate != docSelectionGate.end() && signal != SelectionChanges::MsgSource::Internal) { + SelectionGate* gate = foundGate->second; + App::ElementNamePair elementName; auto pObject = pDoc->getObject(pObjectName); if (!pObject) { @@ -852,14 +845,14 @@ int SelectionSingleton::setPreselect( } const char* subelement = pSubName; - if (gateResolve != ResolveMode::NoResolve) { + if (gate->resolveMode != ResolveMode::NoResolve) { auto& newElementName = elementName.newName; auto& oldElementName = elementName.oldName; pObject = App::GeoFeature::resolveElement(pObject, pSubName, elementName); if (!pObject) { return 0; } - if (gateResolve > ResolveMode::OldStyleElement) { + if (gate->resolveMode > ResolveMode::OldStyleElement) { subelement = !newElementName.empty() ? newElementName.c_str() : oldElementName.c_str(); } @@ -867,10 +860,10 @@ int SelectionSingleton::setPreselect( subelement = oldElementName.c_str(); } } - if (!ActiveGate->allow(pObject->getDocument(), pObject, subelement)) { + if (!gate->allow(pObject->getDocument(), pObject, subelement)) { QString msg; - if (ActiveGate->notAllowedReason.length() > 0) { - msg = QObject::tr(ActiveGate->notAllowedReason.c_str()); + if (gate->notAllowedReason.length() > 0) { + msg = QObject::tr(gate->notAllowedReason.c_str()); } else { msg = QCoreApplication::translate("SelectionFilter", "Not allowed:"); @@ -1058,7 +1051,9 @@ void SelectionSingleton::rmvPreselect(bool signal) hy = 0; hz = 0; - if (ActiveGate && getMainWindow()) { + App::Document* activeDoc = getDocument(nullptr); + auto foundGate = docSelectionGate.find(activeDoc); + if (foundGate != docSelectionGate.end() && getMainWindow()) { Gui::MDIView* mdi = Gui::Application::Instance->activeDocument()->getActiveView(); mdi->restoreOverrideCursor(); } @@ -1075,33 +1070,42 @@ const SelectionChanges& SelectionSingleton::getPreselection() const } // add a SelectionGate to control what is selectable -void SelectionSingleton::addSelectionGate(Gui::SelectionGate* gate, ResolveMode resolve) +void SelectionSingleton::addSelectionGate(Gui::SelectionGate* gate, ResolveMode resolve, const char* pDocName) { - if (ActiveGate) { - rmvSelectionGate(); + App::Document* doc = getDocument(pDocName); + if (!doc) { + return; } + rmvSelectionGate(doc); - ActiveGate = gate; - gateResolve = resolve; + gate->resolveMode = resolve; + docSelectionGate[doc] = gate; } // remove the active SelectionGate -void SelectionSingleton::rmvSelectionGate() +void SelectionSingleton::rmvSelectionGate(App::Document* doc) { - if (ActiveGate) { - delete ActiveGate; - ActiveGate = nullptr; + auto foundGate = docSelectionGate.find(doc); + if (foundGate != docSelectionGate.end()) { + delete foundGate->second; + docSelectionGate.erase(foundGate); - Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (doc) { - // if a document is about to be closed it has no MDI view any more - Gui::MDIView* mdi = doc->getActiveView(); - if (mdi) { + // if a document is about to be closed it has no MDI view any more + if (Gui::Document* guiDoc = Gui::Application::Instance->getDocument(doc)) { + if (Gui::MDIView* mdi = guiDoc->getActiveView()) { mdi->restoreOverrideCursor(); } } } } +void SelectionSingleton::rmvSelectionGate(const char* pDocName) +{ + App::Document* doc = getDocument(pDocName); + if (!doc) { + return; + } + rmvSelectionGate(doc); +} App::Document* SelectionSingleton::getDocument(const char* pDocName) const @@ -1217,16 +1221,26 @@ bool SelectionSingleton::addSelection( temp.y = y; temp.z = z; + App::Document* doc = getDocument(pDocName); + if (!doc) { + return false; + } + auto foundGate = docSelectionGate.find(doc); // check for a Selection Gate - if (ActiveGate) { + if (foundGate != docSelectionGate.end()) { + SelectionGate* gate = foundGate->second; const char* subelement = nullptr; - auto pObject - = getObjectOfType(temp, App::DocumentObject::getClassTypeId(), gateResolve, &subelement); - if (!ActiveGate->allow(pObject ? pObject->getDocument() : temp.pDoc, pObject, subelement)) { + auto pObject = getObjectOfType( + temp, + App::DocumentObject::getClassTypeId(), + gate->resolveMode, + &subelement + ); + if (!gate->allow(pObject ? pObject->getDocument() : temp.pDoc, pObject, subelement)) { if (getMainWindow()) { QString msg; - if (ActiveGate->notAllowedReason.length() > 0) { - msg = QObject::tr(ActiveGate->notAllowedReason.c_str()); + if (gate->notAllowedReason.length() > 0) { + msg = QObject::tr(gate->notAllowedReason.c_str()); } else { msg = QCoreApplication::translate( @@ -1238,7 +1252,7 @@ bool SelectionSingleton::addSelection( Gui::MDIView* mdi = Gui::Application::Instance->activeDocument()->getActiveView(); mdi->setOverrideCursor(Qt::ForbiddenCursor); } - ActiveGate->notAllowedReason.clear(); + gate->notAllowedReason.clear(); QApplication::beep(); return false; } @@ -2178,8 +2192,7 @@ SelectionSingleton::SelectionSingleton() hx = 0; hy = 0; hz = 0; - ActiveGate = nullptr; - gateResolve = ResolveMode::OldStyleElement; + // NOLINTBEGIN App::GetApplication().signalDeletedObject.connect( std::bind(&Gui::SelectionSingleton::slotDeletedObject, this, sp::_1) @@ -3063,13 +3076,14 @@ PyObject* SelectionSingleton::sAddSelectionGate(PyObject* /*self*/, PyObject* ar PyObject* SelectionSingleton::sRemoveSelectionGate(PyObject* /*self*/, PyObject* args) { - if (!PyArg_ParseTuple(args, "")) { + const char* pDocName = ""; + if (!PyArg_ParseTuple(args, "|s", &pDocName)) { return nullptr; } PY_TRY { - Selection().rmvSelectionGate(); + Selection().rmvSelectionGate(pDocName); Py_Return; } PY_CATCH; diff --git a/src/Gui/Selection/Selection.h b/src/Gui/Selection/Selection.h index 4244a21f13..4929f08158 100644 --- a/src/Gui/Selection/Selection.h +++ b/src/Gui/Selection/Selection.h @@ -284,6 +284,7 @@ public: * literal into QT_TR_NOOP() for translatability. */ std::string notAllowedReason; + ResolveMode resolveMode; }; /** SelectionGateFilterExternal @@ -415,10 +416,19 @@ public: void setPreselectCoord(float x, float y, float z); /// returns the present preselection const SelectionChanges& getPreselection() const; - /// add a SelectionGate to control what is selectable - void addSelectionGate(Gui::SelectionGate* gate, ResolveMode resolve = ResolveMode::OldStyleElement); - /// remove the active SelectionGate - void rmvSelectionGate(); + /// add a SelectionGate to control what is selectable in a document's scope, by default the + /// active document is selected + // which is usually the intended behavior + void addSelectionGate( + Gui::SelectionGate* gate, + ResolveMode resolve = ResolveMode::OldStyleElement, + const char* pDocName = nullptr + ); + /// remove the document's SelectionGate, by default the active document is selected, which is + /// usually the intended behavior + void rmvSelectionGate(const char* pDocName = nullptr); + /// remove the document's SelectionGate (assumes valid pointer) + void rmvSelectionGate(App::Document* doc); int disableCommandLog(); int enableCommandLog(bool silent = false); @@ -833,13 +843,15 @@ protected: static SelectionSingleton* _pcSingleton; + // each document can have at most 1 selection gate active + std::map docSelectionGate; + + // Preselection helpers - it's a mess std::string DocName; std::string FeatName; std::string SubName; float hx, hy, hz; - Gui::SelectionGate* ActiveGate; - ResolveMode gateResolve; int logDisabled = 0; bool logHasSelection = false;