| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| |
|
| | #include <array>
|
| | #include <set>
|
| | #include <boost/algorithm/string/predicate.hpp>
|
| | #include <QApplication>
|
| |
|
| |
|
| | #include <App/Application.h>
|
| | #include <App/Document.h>
|
| | #include <App/DocumentObject.h>
|
| | #include <App/DocumentObjectPy.h>
|
| | #include <App/GeoFeature.h>
|
| | #include <Base/Console.h>
|
| | #include <Base/Exception.h>
|
| | #include <Base/Interpreter.h>
|
| | #include <Base/Tools.h>
|
| | #include <Base/PyWrapParseTupleAndKeywords.h>
|
| | #include <Base/UnitsApi.h>
|
| |
|
| | #include "Selection.h"
|
| | #include "SelectionObject.h"
|
| | #include "Application.h"
|
| | #include "Document.h"
|
| | #include "Macro.h"
|
| | #include "MainWindow.h"
|
| | #include "MDIView.h"
|
| | #include "SelectionFilter.h"
|
| | #include "SelectionFilterPy.h"
|
| | #include "SelectionObserverPython.h"
|
| | #include "Tree.h"
|
| | #include "ViewProvider.h"
|
| | #include "ViewProviderDocumentObject.h"
|
| |
|
| |
|
| | FC_LOG_LEVEL_INIT("Selection", false, true, true)
|
| |
|
| | using namespace Gui;
|
| | using namespace std;
|
| | namespace sp = std::placeholders;
|
| |
|
| | SelectionGateFilterExternal::SelectionGateFilterExternal(const char* docName, const char* objName)
|
| | {
|
| | if (docName) {
|
| | DocName = docName;
|
| | if (objName) {
|
| | ObjName = objName;
|
| | }
|
| | }
|
| | }
|
| |
|
| | bool SelectionGateFilterExternal::allow(App::Document* doc, App::DocumentObject* obj, const char*)
|
| | {
|
| | if (!doc || !obj) {
|
| | return true;
|
| | }
|
| | if (!DocName.empty() && doc->getName() != DocName) {
|
| | notAllowedReason = "Cannot select external object";
|
| | }
|
| | else if (!ObjName.empty() && ObjName == obj->getNameInDocument()) {
|
| | notAllowedReason = "Cannot select self";
|
| | }
|
| | else {
|
| | return true;
|
| | }
|
| | return false;
|
| | }
|
| |
|
| |
|
| |
|
| | SelectionObserver::SelectionObserver(bool attach, ResolveMode resolve)
|
| | : resolve(resolve)
|
| | , blockedSelection(false)
|
| | {
|
| | if (attach) {
|
| | attachSelection();
|
| | }
|
| | }
|
| |
|
| | SelectionObserver::SelectionObserver(const ViewProviderDocumentObject* vp, bool attach, ResolveMode resolve)
|
| | : resolve(resolve)
|
| | , blockedSelection(false)
|
| | {
|
| | if (vp && vp->getObject() && vp->getObject()->getDocument()) {
|
| | filterDocName = vp->getObject()->getDocument()->getName();
|
| | filterObjName = vp->getObject()->getNameInDocument();
|
| | }
|
| | if (attach) {
|
| | attachSelection();
|
| | }
|
| | }
|
| |
|
| |
|
| | SelectionObserver::~SelectionObserver()
|
| | {
|
| | detachSelection();
|
| | }
|
| |
|
| | bool SelectionObserver::blockSelection(bool block)
|
| | {
|
| | bool ok = blockedSelection;
|
| | blockedSelection = block;
|
| | return ok;
|
| | }
|
| |
|
| | bool SelectionObserver::isSelectionBlocked() const
|
| | {
|
| | return blockedSelection;
|
| | }
|
| |
|
| | bool SelectionObserver::isSelectionAttached() const
|
| | {
|
| | return connectSelection.connected();
|
| | }
|
| |
|
| | void SelectionObserver::attachSelection()
|
| | {
|
| | if (!connectSelection.connected()) {
|
| | bool newStyle = (resolve >= ResolveMode::NewStyleElement);
|
| | bool oldStyle = (resolve == ResolveMode::OldStyleElement);
|
| | auto& signal = newStyle ? Selection().signalSelectionChanged3
|
| | : oldStyle ? Selection().signalSelectionChanged2
|
| | : Selection().signalSelectionChanged;
|
| |
|
| | connectSelection = signal.connect(
|
| | std::bind(&SelectionObserver::_onSelectionChanged, this, sp::_1)
|
| | );
|
| |
|
| |
|
| | if (!filterDocName.empty()) {
|
| | Selection().addSelectionGate(
|
| | new SelectionGateFilterExternal(filterDocName.c_str(), filterObjName.c_str())
|
| | );
|
| | }
|
| | }
|
| | }
|
| |
|
| | void SelectionObserver::_onSelectionChanged(const SelectionChanges& msg)
|
| | {
|
| | try {
|
| | if (blockedSelection) {
|
| | return;
|
| | }
|
| | onSelectionChanged(msg);
|
| | }
|
| | catch (Base::Exception& e) {
|
| | e.reportException();
|
| | FC_ERR("Unhandled Base::Exception caught in selection observer: ");
|
| | }
|
| | catch (std::exception& e) {
|
| | FC_ERR("Unhandled std::exception caught in selection observer: " << e.what());
|
| | }
|
| | catch (...) {
|
| | FC_ERR("Unhandled unknown exception caught in selection observer");
|
| | }
|
| | }
|
| |
|
| | void SelectionObserver::detachSelection()
|
| | {
|
| | if (connectSelection.connected()) {
|
| | connectSelection.disconnect();
|
| | if (!filterDocName.empty()) {
|
| | Selection().rmvSelectionGate();
|
| | }
|
| | }
|
| | }
|
| |
|
| |
|
| |
|
| | bool SelectionSingleton::hasSelection() const
|
| | {
|
| | return !_SelList.empty();
|
| | }
|
| |
|
| | bool SelectionSingleton::hasPreselection() const
|
| | {
|
| | return !CurrentPreselection.Object.getObjectName().empty();
|
| | }
|
| |
|
| | std::vector<SelectionSingleton::SelObj> SelectionSingleton::getCompleteSelection(ResolveMode resolve) const
|
| | {
|
| | return getSelection("*", resolve);
|
| | }
|
| |
|
| | std::vector<SelectionSingleton::SelObj> SelectionSingleton::getSelection(
|
| | const char* pDocName,
|
| | ResolveMode resolve,
|
| | bool single
|
| | ) const
|
| | {
|
| | std::vector<SelObj> temp;
|
| | if (single) {
|
| | temp.reserve(1);
|
| | }
|
| | SelObj tempSelObj;
|
| |
|
| | App::Document* pcDoc = nullptr;
|
| | if (!pDocName || strcmp(pDocName, "*") != 0) {
|
| | pcDoc = getDocument(pDocName);
|
| | if (!pcDoc) {
|
| | return temp;
|
| | }
|
| | }
|
| |
|
| | std::map<App::DocumentObject*, std::set<std::string>> objMap;
|
| |
|
| | for (auto& sel : _SelList) {
|
| | if (!sel.pDoc) {
|
| | continue;
|
| | }
|
| | const char* subelement = nullptr;
|
| | auto obj = getObjectOfType(sel, App::DocumentObject::getClassTypeId(), resolve, &subelement);
|
| | if (!obj || (pcDoc && sel.pObject->getDocument() != pcDoc)) {
|
| | continue;
|
| | }
|
| |
|
| |
|
| | if (resolve != ResolveMode::NoResolve
|
| | && !objMap[obj].insert(std::string(subelement ? subelement : "")).second) {
|
| | continue;
|
| | }
|
| |
|
| | if (single && !temp.empty()) {
|
| | temp.clear();
|
| | break;
|
| | }
|
| |
|
| | tempSelObj.DocName = obj->getDocument()->getName();
|
| | tempSelObj.FeatName = obj->getNameInDocument();
|
| | tempSelObj.SubName = subelement;
|
| | tempSelObj.TypeName = obj->getTypeId().getName();
|
| | tempSelObj.pObject = obj;
|
| | tempSelObj.pResolvedObject = sel.pResolvedObject;
|
| | tempSelObj.pDoc = obj->getDocument();
|
| | tempSelObj.x = sel.x;
|
| | tempSelObj.y = sel.y;
|
| | tempSelObj.z = sel.z;
|
| |
|
| | temp.push_back(tempSelObj);
|
| | }
|
| |
|
| | return temp;
|
| | }
|
| |
|
| | bool SelectionSingleton::hasSelection(const char* doc, ResolveMode resolve) const
|
| | {
|
| | App::Document* pcDoc = nullptr;
|
| | if (!doc || strcmp(doc, "*") != 0) {
|
| | pcDoc = getDocument(doc);
|
| | if (!pcDoc) {
|
| | return false;
|
| | }
|
| | }
|
| | for (auto& sel : _SelList) {
|
| | if (!sel.pDoc) {
|
| | continue;
|
| | }
|
| | auto obj = getObjectOfType(sel, App::DocumentObject::getClassTypeId(), resolve);
|
| | if (obj && (!pcDoc || sel.pObject->getDocument() == pcDoc)) {
|
| | return true;
|
| | }
|
| | }
|
| |
|
| | return false;
|
| | }
|
| |
|
| | bool SelectionSingleton::hasSubSelection(const char* doc, bool subElement) const
|
| | {
|
| | App::Document* pcDoc = nullptr;
|
| | if (!doc || strcmp(doc, "*") != 0) {
|
| | pcDoc = getDocument(doc);
|
| | if (!pcDoc) {
|
| | return false;
|
| | }
|
| | }
|
| | for (auto& sel : _SelList) {
|
| | if (pcDoc && pcDoc != sel.pDoc) {
|
| | continue;
|
| | }
|
| | if (sel.SubName.empty()) {
|
| | continue;
|
| | }
|
| | if (subElement && sel.SubName.back() != '.') {
|
| | return true;
|
| | }
|
| | if (sel.pObject != sel.pResolvedObject) {
|
| | return true;
|
| | }
|
| | }
|
| |
|
| | return false;
|
| | }
|
| |
|
| | std::vector<SelectionSingleton::SelObj> SelectionSingleton::getPickedList(const char* pDocName) const
|
| | {
|
| | std::vector<SelObj> temp;
|
| | SelObj tempSelObj;
|
| |
|
| | App::Document* pcDoc = nullptr;
|
| | if (!pDocName || strcmp(pDocName, "*") != 0) {
|
| | pcDoc = getDocument(pDocName);
|
| | if (!pcDoc) {
|
| | return temp;
|
| | }
|
| | }
|
| |
|
| | for (std::list<_SelObj>::const_iterator It = _PickedList.begin(); It != _PickedList.end(); ++It) {
|
| | if (!pcDoc || It->pDoc == pcDoc) {
|
| | tempSelObj.DocName = It->DocName.c_str();
|
| | tempSelObj.FeatName = It->FeatName.c_str();
|
| | tempSelObj.SubName = It->SubName.c_str();
|
| | tempSelObj.TypeName = It->TypeName.c_str();
|
| | tempSelObj.pObject = It->pObject;
|
| | tempSelObj.pResolvedObject = It->pResolvedObject;
|
| | tempSelObj.pDoc = It->pDoc;
|
| | tempSelObj.x = It->x;
|
| | tempSelObj.y = It->y;
|
| | tempSelObj.z = It->z;
|
| | temp.push_back(tempSelObj);
|
| | }
|
| | }
|
| |
|
| | return temp;
|
| | }
|
| |
|
| | std::vector<Gui::SelectionObject> SelectionSingleton::getSelectionIn(
|
| | App::DocumentObject* container,
|
| | Base::Type typeId,
|
| | bool single
|
| | ) const
|
| | {
|
| | if (!container) {
|
| | return getSelectionEx(nullptr, typeId, ResolveMode::NoResolve, single);
|
| | }
|
| |
|
| | std::vector<SelectionObject> sels
|
| | = getSelectionEx(nullptr, App::DocumentObject::getClassTypeId(), ResolveMode::NoResolve, single);
|
| |
|
| | std::vector<SelectionObject> ret;
|
| | std::map<App::DocumentObject*, size_t> SortMap;
|
| |
|
| | for (auto& sel : sels) {
|
| | auto* rootObj = sel.getObject();
|
| | App::Document* doc = rootObj->getDocument();
|
| | std::vector<std::string> subs = sel.getSubNames();
|
| | bool objPassed = false;
|
| |
|
| | for (size_t i = 0; i < subs.size(); ++i) {
|
| | auto& sub = subs[i];
|
| | App::DocumentObject* newRootObj = nullptr;
|
| | std::string newSub = "";
|
| |
|
| | std::vector<std::string> names = Base::Tools::splitSubName(sub);
|
| |
|
| | if (container == rootObj) {
|
| | objPassed = true;
|
| | }
|
| |
|
| | if (rootObj->isLink()) {
|
| |
|
| | doc = rootObj->getLinkedObject()->getDocument();
|
| | }
|
| |
|
| | for (auto& name : names) {
|
| | App::DocumentObject* obj = doc->getObject(name.c_str());
|
| | if (!obj) {
|
| | newSub += name;
|
| | break;
|
| | }
|
| |
|
| | if (objPassed) {
|
| | if (!newRootObj) {
|
| |
|
| | newRootObj = obj;
|
| | }
|
| | else {
|
| | newSub += name + ".";
|
| | }
|
| | }
|
| |
|
| | if (obj == container) {
|
| | objPassed = true;
|
| | }
|
| | if (obj->isLink()) {
|
| |
|
| | doc = obj->getLinkedObject()->getDocument();
|
| | }
|
| | }
|
| |
|
| | if (newRootObj) {
|
| |
|
| | auto* lastObj = newRootObj->resolve(newSub.c_str());
|
| | if (!lastObj || !lastObj->isDerivedFrom(typeId)) {
|
| | continue;
|
| | }
|
| |
|
| | auto it = SortMap.find(newRootObj);
|
| | if (it != SortMap.end()) {
|
| |
|
| | if (newSub != "") {
|
| | ret[it->second].SubNames.emplace_back(newSub);
|
| | ret[it->second].SelPoses.emplace_back(sel.SelPoses[i]);
|
| | }
|
| | }
|
| | else {
|
| | if (single && !ret.empty()) {
|
| | ret.clear();
|
| | break;
|
| | }
|
| |
|
| | ret.emplace_back(newRootObj);
|
| | if (newSub != "") {
|
| | ret.back().SubNames.emplace_back(newSub);
|
| | ret.back().SelPoses.emplace_back(sel.SelPoses[i]);
|
| | }
|
| | SortMap.insert(std::make_pair(newRootObj, ret.size() - 1));
|
| | }
|
| | }
|
| | }
|
| | }
|
| |
|
| | return ret;
|
| | }
|
| |
|
| | std::vector<SelectionObject> SelectionSingleton::getSelectionEx(
|
| | const char* pDocName,
|
| | Base::Type typeId,
|
| | ResolveMode resolve,
|
| | bool single
|
| | ) const
|
| | {
|
| | return getObjectList(pDocName, typeId, _SelList, resolve, single);
|
| | }
|
| |
|
| | std::vector<SelectionObject> SelectionSingleton::getPickedListEx(
|
| | const char* pDocName,
|
| | Base::Type typeId
|
| | ) const
|
| | {
|
| | return getObjectList(pDocName, typeId, _PickedList, ResolveMode::NoResolve);
|
| | }
|
| |
|
| | std::vector<SelectionObject> SelectionSingleton::getObjectList(
|
| | const char* pDocName,
|
| | Base::Type typeId,
|
| | std::list<_SelObj>& objList,
|
| | ResolveMode resolve,
|
| | bool single
|
| | ) const
|
| | {
|
| | std::vector<SelectionObject> temp;
|
| | if (single) {
|
| | temp.reserve(1);
|
| | }
|
| | std::map<App::DocumentObject*, size_t> SortMap;
|
| |
|
| |
|
| | if (typeId.isBad()) {
|
| | return temp;
|
| | }
|
| |
|
| | App::Document* pcDoc = nullptr;
|
| | if (!pDocName || strcmp(pDocName, "*") != 0) {
|
| | pcDoc = getDocument(pDocName);
|
| | if (!pcDoc) {
|
| | return temp;
|
| | }
|
| | }
|
| |
|
| | for (auto& sel : objList) {
|
| | if (!sel.pDoc) {
|
| | continue;
|
| | }
|
| | const char* subelement = nullptr;
|
| | auto obj = getObjectOfType(sel, typeId, resolve, &subelement);
|
| | if (!obj || (pcDoc && sel.pObject->getDocument() != pcDoc)) {
|
| | continue;
|
| | }
|
| | auto it = SortMap.find(obj);
|
| | if (it != SortMap.end()) {
|
| |
|
| | if (subelement && *subelement) {
|
| | if (resolve != ResolveMode::NoResolve
|
| | && !temp[it->second]._SubNameSet.insert(subelement).second) {
|
| | continue;
|
| | }
|
| | temp[it->second].SubNames.emplace_back(subelement);
|
| | temp[it->second].SelPoses.emplace_back(sel.x, sel.y, sel.z);
|
| | }
|
| | }
|
| | else {
|
| | if (single && !temp.empty()) {
|
| | temp.clear();
|
| | break;
|
| | }
|
| |
|
| | temp.emplace_back(obj);
|
| | if (subelement && *subelement) {
|
| | temp.back().SubNames.emplace_back(subelement);
|
| | temp.back().SelPoses.emplace_back(sel.x, sel.y, sel.z);
|
| | if (resolve != ResolveMode::NoResolve) {
|
| | temp.back()._SubNameSet.insert(subelement);
|
| | }
|
| | }
|
| | SortMap.insert(std::make_pair(obj, temp.size() - 1));
|
| | }
|
| | }
|
| |
|
| | return temp;
|
| | }
|
| |
|
| | bool SelectionSingleton::needPickedList() const
|
| | {
|
| | return _needPickedList;
|
| | }
|
| |
|
| | void SelectionSingleton::enablePickedList(bool enable)
|
| | {
|
| | if (enable != _needPickedList) {
|
| | _needPickedList = enable;
|
| | _PickedList.clear();
|
| | notify(SelectionChanges(SelectionChanges::PickedListChanged));
|
| | }
|
| | }
|
| |
|
| | static void notifyDocumentObjectViewProvider(const SelectionChanges& changes)
|
| | {
|
| | const auto* doc = App::GetApplication().getDocument(changes.pDocName);
|
| | if (!doc) {
|
| | return;
|
| | }
|
| |
|
| | const auto* obj = doc->getObject(changes.pObjectName);
|
| | if (!obj) {
|
| | return;
|
| | }
|
| |
|
| | auto* vp = Application::Instance->getViewProvider(obj);
|
| | if (!vp) {
|
| | return;
|
| | }
|
| |
|
| | vp->onSelectionChanged(changes);
|
| | }
|
| |
|
| | void SelectionSingleton::notify(SelectionChanges&& Chng)
|
| | {
|
| | if (Notifying) {
|
| | NotificationQueue.push_back(std::move(Chng));
|
| | return;
|
| | }
|
| | Base::FlagToggler<bool> flag(Notifying);
|
| | NotificationQueue.push_back(std::move(Chng));
|
| | while (!NotificationQueue.empty()) {
|
| | const auto& msg = NotificationQueue.front();
|
| | bool notify = false;
|
| | switch (msg.Type) {
|
| | case SelectionChanges::AddSelection:
|
| | notify = isSelected(msg.pDocName, msg.pObjectName, msg.pSubName, ResolveMode::NoResolve);
|
| | break;
|
| | case SelectionChanges::RmvSelection:
|
| | notify = !isSelected(msg.pDocName, msg.pObjectName, msg.pSubName, ResolveMode::NoResolve);
|
| | break;
|
| | case SelectionChanges::SetPreselect:
|
| | notify = CurrentPreselection.Type == SelectionChanges::SetPreselect
|
| | && CurrentPreselection.Object == msg.Object;
|
| | break;
|
| | case SelectionChanges::RmvPreselect:
|
| | notify = CurrentPreselection.Type == SelectionChanges::ClrSelection;
|
| | break;
|
| | default:
|
| | notify = true;
|
| | }
|
| | if (notify) {
|
| |
|
| | notifyDocumentObjectViewProvider(msg);
|
| |
|
| | Notify(msg);
|
| | try {
|
| | signalSelectionChanged(msg);
|
| | }
|
| | catch (const boost::exception&) {
|
| |
|
| | Base::Console().warning("notify: Unexpected boost exception\n");
|
| | }
|
| | }
|
| | NotificationQueue.pop_front();
|
| | }
|
| | }
|
| |
|
| | bool SelectionSingleton::hasPickedList() const
|
| | {
|
| | return !_PickedList.empty();
|
| | }
|
| |
|
| | int SelectionSingleton::getAsPropertyLinkSubList(App::PropertyLinkSubList& prop) const
|
| | {
|
| | std::vector<Gui::SelectionObject> sel = this->getSelectionEx();
|
| | std::vector<App::DocumentObject*> objs;
|
| | objs.reserve(sel.size() * 2);
|
| | std::vector<std::string> subs;
|
| | subs.reserve(sel.size() * 2);
|
| | for (auto& selitem : sel) {
|
| | App::DocumentObject* obj = selitem.getObject();
|
| | const std::vector<std::string>& subnames = selitem.getSubNames();
|
| |
|
| |
|
| | if (subnames.empty()) {
|
| | objs.push_back(obj);
|
| | subs.emplace_back();
|
| | }
|
| | else {
|
| | for (const auto& subname : subnames) {
|
| | objs.push_back(obj);
|
| | subs.push_back(subname);
|
| | }
|
| | }
|
| | }
|
| | assert(objs.size() == subs.size());
|
| | prop.setValues(objs, subs);
|
| | return objs.size();
|
| | }
|
| |
|
| | App::DocumentObject* SelectionSingleton::getObjectOfType(
|
| | _SelObj& sel,
|
| | Base::Type typeId,
|
| | ResolveMode resolve,
|
| | const char** subelement
|
| | )
|
| | {
|
| | auto obj = sel.pObject;
|
| | if (!obj || !obj->isAttachedToDocument()) {
|
| | return nullptr;
|
| | }
|
| | const char* subname = sel.SubName.c_str();
|
| | if (resolve != ResolveMode::NoResolve) {
|
| | obj = sel.pResolvedObject;
|
| | if (resolve == ResolveMode::NewStyleElement && !sel.elementName.newName.empty()) {
|
| | subname = sel.elementName.newName.c_str();
|
| | }
|
| | else {
|
| | subname = sel.elementName.oldName.c_str();
|
| | }
|
| | }
|
| |
|
| | if (!obj) {
|
| | return nullptr;
|
| | }
|
| |
|
| | if (!obj->isDerivedFrom(typeId)
|
| | && (resolve != ResolveMode::FollowLink || !obj->getLinkedObject(true)->isDerivedFrom(typeId))) {
|
| | return nullptr;
|
| | }
|
| |
|
| | if (subelement) {
|
| | *subelement = subname;
|
| | }
|
| |
|
| | return obj;
|
| | }
|
| |
|
| | vector<App::DocumentObject*> SelectionSingleton::getObjectsOfType(
|
| | const Base::Type& typeId,
|
| | const char* pDocName,
|
| | ResolveMode resolve
|
| | ) const
|
| | {
|
| | std::vector<App::DocumentObject*> temp;
|
| |
|
| | App::Document* pcDoc = nullptr;
|
| | if (!pDocName || strcmp(pDocName, "*") != 0) {
|
| | pcDoc = getDocument(pDocName);
|
| | if (!pcDoc) {
|
| | return temp;
|
| | }
|
| | }
|
| |
|
| | std::set<App::DocumentObject*> objs;
|
| | for (auto& sel : _SelList) {
|
| | if (pcDoc && pcDoc != sel.pDoc) {
|
| | continue;
|
| | }
|
| | App::DocumentObject* pObject = getObjectOfType(sel, typeId, resolve);
|
| | if (pObject) {
|
| | auto ret = objs.insert(pObject);
|
| | if (ret.second) {
|
| | temp.push_back(pObject);
|
| | }
|
| | }
|
| | }
|
| |
|
| | return temp;
|
| | }
|
| |
|
| | std::vector<App::DocumentObject*> SelectionSingleton::getObjectsOfType(
|
| | const char* typeName,
|
| | const char* pDocName,
|
| | ResolveMode resolve
|
| | ) const
|
| | {
|
| | Base::Type typeId = Base::Type::fromName(typeName);
|
| | if (typeId.isBad()) {
|
| | return {};
|
| | }
|
| | return getObjectsOfType(typeId, pDocName, resolve);
|
| | }
|
| |
|
| | unsigned int SelectionSingleton::countObjectsOfType(
|
| | const Base::Type& typeId,
|
| | const char* pDocName,
|
| | ResolveMode resolve
|
| | ) const
|
| | {
|
| | App::Document* pcDoc = nullptr;
|
| | if (!pDocName || strcmp(pDocName, "*") != 0) {
|
| | pcDoc = getDocument(pDocName);
|
| | if (!pcDoc) {
|
| | return 0;
|
| | }
|
| | }
|
| |
|
| | return std::count_if(_SelList.begin(), _SelList.end(), [&](auto& sel) {
|
| | return (!pcDoc || pcDoc == sel.pDoc) && getObjectOfType(sel, typeId, resolve);
|
| | });
|
| | }
|
| |
|
| | unsigned int SelectionSingleton::countObjectsOfType(
|
| | const char* typeName,
|
| | const char* pDocName,
|
| | ResolveMode resolve
|
| | ) const
|
| | {
|
| | Base::Type typeId = Base::Type::fromName(typeName);
|
| | if (typeId.isBad()) {
|
| | return 0;
|
| | }
|
| | return countObjectsOfType(typeId, pDocName, resolve);
|
| | }
|
| |
|
| |
|
| | void SelectionSingleton::slotSelectionChanged(const SelectionChanges& msg)
|
| | {
|
| | if (msg.Type == SelectionChanges::SetPreselectSignal || msg.Type == SelectionChanges::ShowSelection
|
| | || msg.Type == SelectionChanges::HideSelection) {
|
| | return;
|
| | }
|
| |
|
| | if (!msg.Object.getSubName().empty()) {
|
| | auto pParent = msg.Object.getObject();
|
| | if (!pParent) {
|
| | return;
|
| | }
|
| | App::ElementNamePair elementName;
|
| | auto& newElementName = elementName.newName;
|
| | auto& oldElementName = elementName.oldName;
|
| | auto pObject = App::GeoFeature::resolveElement(pParent, msg.pSubName, elementName);
|
| | if (!pObject) {
|
| | return;
|
| | }
|
| | SelectionChanges msg2(
|
| | msg.Type,
|
| | pObject->getDocument()->getName(),
|
| | pObject->getNameInDocument(),
|
| | !newElementName.empty() ? newElementName.c_str() : oldElementName.c_str(),
|
| | pObject->getTypeId().getName(),
|
| | msg.x,
|
| | msg.y,
|
| | msg.z
|
| | );
|
| |
|
| | try {
|
| | msg2.pOriginalMsg = &msg;
|
| | signalSelectionChanged3(msg2);
|
| |
|
| | msg2.Object.setSubName(oldElementName.c_str());
|
| | msg2.pSubName = msg2.Object.getSubName().c_str();
|
| | signalSelectionChanged2(msg2);
|
| | }
|
| | catch (const boost::exception&) {
|
| |
|
| | Base::Console().warning("slotSelectionChanged: Unexpected boost exception\n");
|
| | }
|
| | }
|
| | else {
|
| | try {
|
| | signalSelectionChanged3(msg);
|
| | signalSelectionChanged2(msg);
|
| | }
|
| | catch (const boost::exception&) {
|
| |
|
| | Base::Console().warning("slotSelectionChanged: Unexpected boost exception\n");
|
| | }
|
| | }
|
| | }
|
| |
|
| | int SelectionSingleton::setPreselect(
|
| | const char* pDocName,
|
| | const char* pObjectName,
|
| | const char* pSubName,
|
| | float x,
|
| | float y,
|
| | float z,
|
| | SelectionChanges::MsgSource signal
|
| | )
|
| | {
|
| | if (!pDocName || !pObjectName) {
|
| | rmvPreselect();
|
| | return 0;
|
| | }
|
| | if (!pSubName) {
|
| | pSubName = "";
|
| | }
|
| |
|
| | if (DocName == pDocName && FeatName == pObjectName && SubName == pSubName) {
|
| | return -1;
|
| | }
|
| |
|
| | rmvPreselect();
|
| |
|
| | if (ActiveGate && signal != SelectionChanges::MsgSource::Internal) {
|
| | App::Document* pDoc = getDocument(pDocName);
|
| | if (!pDoc || !pObjectName) {
|
| | return 0;
|
| | }
|
| | App::ElementNamePair elementName;
|
| | auto pObject = pDoc->getObject(pObjectName);
|
| | if (!pObject) {
|
| | return 0;
|
| | }
|
| |
|
| | const char* subelement = pSubName;
|
| | if (gateResolve != 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) {
|
| | subelement = !newElementName.empty() ? newElementName.c_str()
|
| | : oldElementName.c_str();
|
| | }
|
| | else {
|
| | subelement = oldElementName.c_str();
|
| | }
|
| | }
|
| | if (!ActiveGate->allow(pObject->getDocument(), pObject, subelement)) {
|
| | QString msg;
|
| | if (ActiveGate->notAllowedReason.length() > 0) {
|
| | msg = QObject::tr(ActiveGate->notAllowedReason.c_str());
|
| | }
|
| | else {
|
| | msg = QCoreApplication::translate("SelectionFilter", "Not allowed:");
|
| | }
|
| | msg.append(QStringLiteral(" %1.%2.%3 ")
|
| | .arg(
|
| | QString::fromLatin1(pDocName),
|
| | QString::fromLatin1(pObjectName),
|
| | QString::fromLatin1(pSubName)
|
| | ));
|
| |
|
| | if (getMainWindow()) {
|
| | getMainWindow()->showMessage(msg);
|
| | Gui::MDIView* mdi = Gui::Application::Instance->activeDocument()->getActiveView();
|
| | mdi->setOverrideCursor(QCursor(Qt::ForbiddenCursor));
|
| | }
|
| | return 0;
|
| | }
|
| | Gui::MDIView* mdi = Gui::Application::Instance->activeDocument()->getActiveView();
|
| | mdi->restoreOverrideCursor();
|
| | }
|
| |
|
| | DocName = pDocName;
|
| | FeatName = pObjectName;
|
| | SubName = pSubName;
|
| | hx = x;
|
| | hy = y;
|
| | hz = z;
|
| |
|
| |
|
| | SelectionChanges Chng(
|
| | signal == SelectionChanges::MsgSource::Internal ? SelectionChanges::SetPreselectSignal
|
| | : SelectionChanges::SetPreselect,
|
| | DocName,
|
| | FeatName,
|
| | SubName,
|
| | std::string(),
|
| | x,
|
| | y,
|
| | z,
|
| | signal
|
| | );
|
| |
|
| | if (Chng.Type == SelectionChanges::SetPreselect) {
|
| | CurrentPreselection = Chng;
|
| | FC_TRACE("preselect " << DocName << '#' << FeatName << '.' << SubName);
|
| | }
|
| | else {
|
| | FC_TRACE("preselect signal " << DocName << '#' << FeatName << '.' << SubName);
|
| | }
|
| |
|
| | notify(Chng);
|
| |
|
| | if (signal == SelectionChanges::MsgSource::Internal && !DocName.empty()) {
|
| | FC_TRACE("preselect " << DocName << '#' << FeatName << '.' << SubName);
|
| | Chng.Type = SelectionChanges::SetPreselect;
|
| | CurrentPreselection = Chng;
|
| | notify(std::move(Chng));
|
| | }
|
| |
|
| |
|
| | return DocName.empty() ? 0 : 1;
|
| | }
|
| |
|
| | namespace Gui
|
| | {
|
| | std::array<std::pair<double, std::string>, 3> schemaTranslatePoint(
|
| | double x,
|
| | double y,
|
| | double z,
|
| | double precision
|
| | )
|
| | {
|
| | Base::Quantity mmx(Base::Quantity::MilliMetre);
|
| | mmx.setValue(fabs(x) > precision ? x : 0.0);
|
| | Base::Quantity mmy(Base::Quantity::MilliMetre);
|
| | mmy.setValue(fabs(y) > precision ? y : 0.0);
|
| | Base::Quantity mmz(Base::Quantity::MilliMetre);
|
| | mmz.setValue(fabs(z) > precision ? z : 0.0);
|
| |
|
| | double xfactor, yfactor, zfactor;
|
| | std::string xunit, yunit, zunit;
|
| |
|
| | Base::UnitsApi::schemaTranslate(mmx, xfactor, xunit);
|
| | Base::UnitsApi::schemaTranslate(mmy, yfactor, yunit);
|
| | Base::UnitsApi::schemaTranslate(mmz, zfactor, zunit);
|
| |
|
| | double xuser = fabs(x) > precision ? x / xfactor : 0.0;
|
| | double yuser = fabs(y) > precision ? y / yfactor : 0.0;
|
| | double zuser = fabs(z) > precision ? z / zfactor : 0.0;
|
| |
|
| | std::array<std::pair<double, std::string>, 3> ret
|
| | = {std::make_pair(xuser, xunit), std::make_pair(yuser, yunit), std::make_pair(zuser, zunit)};
|
| | return ret;
|
| | }
|
| |
|
| | QString getPreselectionInfo(
|
| | const char* documentName,
|
| | const char* objectName,
|
| | const char* subElementName,
|
| | float x,
|
| | float y,
|
| | float z,
|
| | double precision
|
| | )
|
| | {
|
| | auto pts = schemaTranslatePoint(x, y, z, precision);
|
| |
|
| | int numberDecimals = std::min(6, static_cast<int>(Base::UnitsApi::getDecimals()));
|
| |
|
| | QString message = QStringLiteral("Preselected: %1.%2.%3 (%4 %5, %6 %7, %8 %9)")
|
| | .arg(QString::fromUtf8(documentName))
|
| | .arg(QString::fromUtf8(objectName))
|
| | .arg(QString::fromUtf8(subElementName))
|
| | .arg(QString::number(pts[0].first, 'f', numberDecimals))
|
| | .arg(QString::fromStdString(pts[0].second))
|
| | .arg(QString::number(pts[1].first, 'f', numberDecimals))
|
| | .arg(QString::fromStdString(pts[1].second))
|
| | .arg(QString::number(pts[2].first, 'f', numberDecimals))
|
| | .arg(QString::fromStdString(pts[2].second));
|
| | return message;
|
| | }
|
| |
|
| | void printPreselectionInfo(
|
| | const char* documentName,
|
| | const char* objectName,
|
| | const char* subElementName,
|
| | float x,
|
| | float y,
|
| | float z,
|
| | double precision
|
| | )
|
| | {
|
| | if (getMainWindow()) {
|
| | QString message
|
| | = getPreselectionInfo(documentName, objectName, subElementName, x, y, z, precision);
|
| | getMainWindow()->showMessage(message);
|
| | }
|
| | }
|
| | }
|
| |
|
| | void SelectionSingleton::setPreselectCoord(float x, float y, float z)
|
| | {
|
| |
|
| | if (CurrentPreselection.Object.getObjectName().empty()) {
|
| | return;
|
| | }
|
| |
|
| | CurrentPreselection.x = x;
|
| | CurrentPreselection.y = y;
|
| | CurrentPreselection.z = z;
|
| |
|
| | printPreselectionInfo(
|
| | CurrentPreselection.pDocName,
|
| | CurrentPreselection.pObjectName,
|
| | CurrentPreselection.pSubName,
|
| | x,
|
| | y,
|
| | z,
|
| | 0.0
|
| | );
|
| | }
|
| |
|
| | void SelectionSingleton::rmvPreselect(bool signal)
|
| | {
|
| | if (DocName.empty()) {
|
| | return;
|
| | }
|
| |
|
| | if (signal) {
|
| | SelectionChanges Chng(SelectionChanges::RmvPreselectSignal, DocName, FeatName, SubName);
|
| | notify(std::move(Chng));
|
| | return;
|
| | }
|
| |
|
| | SelectionChanges Chng(SelectionChanges::RmvPreselect, DocName, FeatName, SubName);
|
| |
|
| |
|
| | CurrentPreselection = SelectionChanges();
|
| |
|
| | DocName = "";
|
| | FeatName = "";
|
| | SubName = "";
|
| | hx = 0;
|
| | hy = 0;
|
| | hz = 0;
|
| |
|
| | if (ActiveGate && getMainWindow()) {
|
| | Gui::MDIView* mdi = Gui::Application::Instance->activeDocument()->getActiveView();
|
| | mdi->restoreOverrideCursor();
|
| | }
|
| |
|
| | FC_TRACE("rmv preselect");
|
| |
|
| |
|
| | notify(std::move(Chng));
|
| | }
|
| |
|
| | const SelectionChanges& SelectionSingleton::getPreselection() const
|
| | {
|
| | return CurrentPreselection;
|
| | }
|
| |
|
| |
|
| | void SelectionSingleton::addSelectionGate(Gui::SelectionGate* gate, ResolveMode resolve)
|
| | {
|
| | if (ActiveGate) {
|
| | rmvSelectionGate();
|
| | }
|
| |
|
| | ActiveGate = gate;
|
| | gateResolve = resolve;
|
| | }
|
| |
|
| |
|
| | void SelectionSingleton::rmvSelectionGate()
|
| | {
|
| | if (ActiveGate) {
|
| | delete ActiveGate;
|
| | ActiveGate = nullptr;
|
| |
|
| | Gui::Document* doc = Gui::Application::Instance->activeDocument();
|
| | if (doc) {
|
| |
|
| | Gui::MDIView* mdi = doc->getActiveView();
|
| | if (mdi) {
|
| | mdi->restoreOverrideCursor();
|
| | }
|
| | }
|
| | }
|
| | }
|
| |
|
| |
|
| | App::Document* SelectionSingleton::getDocument(const char* pDocName) const
|
| | {
|
| | if (!Base::Tools::isNullOrEmpty(pDocName)) {
|
| | return App::GetApplication().getDocument(pDocName);
|
| | }
|
| | else {
|
| | return App::GetApplication().getActiveDocument();
|
| | }
|
| | }
|
| |
|
| | int SelectionSingleton::disableCommandLog()
|
| | {
|
| | if (!logDisabled) {
|
| | logHasSelection = hasSelection();
|
| | }
|
| | return ++logDisabled;
|
| | }
|
| |
|
| | int SelectionSingleton::enableCommandLog(bool silent)
|
| | {
|
| | --logDisabled;
|
| | if (!logDisabled && !silent) {
|
| | auto manager = Application::Instance->macroManager();
|
| | if (!hasSelection()) {
|
| | if (logHasSelection) {
|
| | manager->addLine(MacroManager::Cmt, "Gui.Selection.clearSelection()");
|
| | }
|
| | }
|
| | else {
|
| | for (auto& sel : _SelList) {
|
| | sel.log();
|
| | }
|
| | }
|
| | }
|
| | return logDisabled;
|
| | }
|
| |
|
| | void SelectionSingleton::_SelObj::log(bool remove, bool clearPreselect)
|
| | {
|
| | if (logged && !remove) {
|
| | return;
|
| | }
|
| | logged = true;
|
| | std::ostringstream ss;
|
| | ss << "Gui.Selection." << (remove ? "removeSelection" : "addSelection") << "('" << DocName
|
| | << "','" << FeatName << "'";
|
| | if (!SubName.empty()) {
|
| | if (!elementName.oldName.empty() && !elementName.newName.empty()) {
|
| | ss << ",'" << SubName.substr(0, SubName.size() - elementName.newName.size())
|
| | << elementName.oldName << "'";
|
| | }
|
| | else {
|
| | ss << ",'" << SubName << "'";
|
| | }
|
| | }
|
| | if (!remove && (x || y || z || !clearPreselect)) {
|
| | if (SubName.empty()) {
|
| | ss << ",''";
|
| | }
|
| | ss << ',' << x << ',' << y << ',' << z;
|
| | if (!clearPreselect) {
|
| | ss << ",False";
|
| | }
|
| | }
|
| | ss << ')';
|
| | Application::Instance->macroManager()->addLine(MacroManager::Cmt, ss.str().c_str());
|
| | }
|
| |
|
| | bool SelectionSingleton::addSelection(
|
| | const char* pDocName,
|
| | const char* pObjectName,
|
| | const char* pSubName,
|
| | float x,
|
| | float y,
|
| | float z,
|
| | const std::vector<SelObj>* pickedList,
|
| | bool clearPreselect
|
| | )
|
| | {
|
| | if (pickedList) {
|
| | _PickedList.clear();
|
| | for (const auto& sel : *pickedList) {
|
| | _PickedList.emplace_back();
|
| | auto& s = _PickedList.back();
|
| | s.DocName = sel.DocName;
|
| | s.FeatName = sel.FeatName;
|
| | s.SubName = sel.SubName;
|
| | s.TypeName = sel.TypeName;
|
| | s.pObject = sel.pObject;
|
| | s.pDoc = sel.pDoc;
|
| | s.x = sel.x;
|
| | s.y = sel.y;
|
| | s.z = sel.z;
|
| | }
|
| | notify(SelectionChanges(SelectionChanges::PickedListChanged));
|
| | }
|
| |
|
| | _SelObj temp;
|
| | int ret = checkSelection(pDocName, pObjectName, pSubName, ResolveMode::NoResolve, temp);
|
| | if (ret != 0) {
|
| | return false;
|
| | }
|
| |
|
| | temp.x = x;
|
| | temp.y = y;
|
| | temp.z = z;
|
| |
|
| |
|
| | if (ActiveGate) {
|
| | const char* subelement = nullptr;
|
| | auto pObject
|
| | = getObjectOfType(temp, App::DocumentObject::getClassTypeId(), gateResolve, &subelement);
|
| | if (!ActiveGate->allow(pObject ? pObject->getDocument() : temp.pDoc, pObject, subelement)) {
|
| | if (getMainWindow()) {
|
| | QString msg;
|
| | if (ActiveGate->notAllowedReason.length() > 0) {
|
| | msg = QObject::tr(ActiveGate->notAllowedReason.c_str());
|
| | }
|
| | else {
|
| | msg = QCoreApplication::translate(
|
| | "SelectionFilter",
|
| | "Selection not allowed by filter"
|
| | );
|
| | }
|
| | getMainWindow()->showMessage(msg);
|
| | Gui::MDIView* mdi = Gui::Application::Instance->activeDocument()->getActiveView();
|
| | mdi->setOverrideCursor(Qt::ForbiddenCursor);
|
| | }
|
| | ActiveGate->notAllowedReason.clear();
|
| | QApplication::beep();
|
| | return false;
|
| | }
|
| | }
|
| |
|
| | if (!logDisabled) {
|
| | temp.log(false, clearPreselect);
|
| | }
|
| |
|
| | _SelList.push_back(temp);
|
| | _SelStackForward.clear();
|
| |
|
| | if (clearPreselect) {
|
| | rmvPreselect();
|
| | }
|
| |
|
| | SelectionChanges Chng(
|
| | SelectionChanges::AddSelection,
|
| | temp.DocName,
|
| | temp.FeatName,
|
| | temp.SubName,
|
| | temp.TypeName,
|
| | x,
|
| | y,
|
| | z
|
| | );
|
| |
|
| | FC_LOG(
|
| | "Add Selection " << Chng.pDocName << '#' << Chng.pObjectName << '.' << Chng.pSubName << " ("
|
| | << x << ", " << y << ", " << z << ')'
|
| | );
|
| |
|
| | notify(std::move(Chng));
|
| |
|
| | getMainWindow()->updateActions();
|
| |
|
| | rmvPreselect(true);
|
| |
|
| |
|
| |
|
| | return isSelected(temp.DocName.c_str(), temp.FeatName.c_str(), temp.SubName.c_str());
|
| | }
|
| |
|
| | void SelectionSingleton::selStackPush(bool clearForward, bool overwrite)
|
| | {
|
| | static int stackSize;
|
| | if (!stackSize) {
|
| | stackSize = App::GetApplication()
|
| | .GetParameterGroupByPath("User parameter:BaseApp/Preferences/View")
|
| | ->GetInt("SelectionStackSize", 100);
|
| | }
|
| | if (clearForward) {
|
| | _SelStackForward.clear();
|
| | }
|
| | if (_SelList.empty()) {
|
| | return;
|
| | }
|
| | if ((int)_SelStackBack.size() >= stackSize) {
|
| | _SelStackBack.pop_front();
|
| | }
|
| | SelStackItem item;
|
| | for (auto& sel : _SelList) {
|
| | item.emplace(sel.DocName.c_str(), sel.FeatName.c_str(), sel.SubName.c_str());
|
| | }
|
| | if (!_SelStackBack.empty() && _SelStackBack.back() == item) {
|
| | return;
|
| | }
|
| | if (!overwrite || _SelStackBack.empty()) {
|
| | _SelStackBack.emplace_back();
|
| | }
|
| | _SelStackBack.back() = std::move(item);
|
| | }
|
| |
|
| | void SelectionSingleton::selStackGoBack(int count)
|
| | {
|
| | if ((int)_SelStackBack.size() < count) {
|
| | count = _SelStackBack.size();
|
| | }
|
| | if (count <= 0) {
|
| | return;
|
| | }
|
| | if (!_SelList.empty()) {
|
| | selStackPush(false, true);
|
| | clearCompleteSelection();
|
| | }
|
| | else {
|
| | --count;
|
| | }
|
| | for (int i = 0; i < count; ++i) {
|
| | _SelStackForward.push_front(std::move(_SelStackBack.back()));
|
| | _SelStackBack.pop_back();
|
| | }
|
| | std::deque<SelStackItem> tmpStack;
|
| | _SelStackForward.swap(tmpStack);
|
| | while (!_SelStackBack.empty()) {
|
| | bool found = false;
|
| | for (auto& sobjT : _SelStackBack.back()) {
|
| | if (sobjT.getSubObject()) {
|
| | addSelection(
|
| | sobjT.getDocumentName().c_str(),
|
| | sobjT.getObjectName().c_str(),
|
| | sobjT.getSubName().c_str()
|
| | );
|
| | found = true;
|
| | }
|
| | }
|
| | if (found) {
|
| | break;
|
| | }
|
| | tmpStack.push_front(std::move(_SelStackBack.back()));
|
| | _SelStackBack.pop_back();
|
| | }
|
| | _SelStackForward = std::move(tmpStack);
|
| | getMainWindow()->updateActions();
|
| | }
|
| |
|
| | void SelectionSingleton::selStackGoForward(int count)
|
| | {
|
| | if ((int)_SelStackForward.size() < count) {
|
| | count = _SelStackForward.size();
|
| | }
|
| | if (count <= 0) {
|
| | return;
|
| | }
|
| | if (!_SelList.empty()) {
|
| | selStackPush(false, true);
|
| | clearCompleteSelection();
|
| | }
|
| | for (int i = 0; i < count; ++i) {
|
| | _SelStackBack.push_back(_SelStackForward.front());
|
| | _SelStackForward.pop_front();
|
| | }
|
| | std::deque<SelStackItem> tmpStack;
|
| | _SelStackForward.swap(tmpStack);
|
| | while (true) {
|
| | bool found = false;
|
| | for (auto& sobjT : _SelStackBack.back()) {
|
| | if (sobjT.getSubObject()) {
|
| | addSelection(
|
| | sobjT.getDocumentName().c_str(),
|
| | sobjT.getObjectName().c_str(),
|
| | sobjT.getSubName().c_str()
|
| | );
|
| | found = true;
|
| | }
|
| | }
|
| | if (found || tmpStack.empty()) {
|
| | break;
|
| | }
|
| | _SelStackBack.push_back(tmpStack.front());
|
| | tmpStack.pop_front();
|
| | }
|
| | _SelStackForward = std::move(tmpStack);
|
| | getMainWindow()->updateActions();
|
| | }
|
| |
|
| | std::vector<SelectionObject> SelectionSingleton::selStackGet(
|
| | const char* pDocName,
|
| | ResolveMode resolve,
|
| | int index
|
| | ) const
|
| | {
|
| | const SelStackItem* item = nullptr;
|
| | if (index >= 0) {
|
| | if (index >= (int)_SelStackBack.size()) {
|
| | return {};
|
| | }
|
| | item = &_SelStackBack[_SelStackBack.size() - 1 - index];
|
| | }
|
| | else {
|
| | index = -index - 1;
|
| | if (index >= (int)_SelStackForward.size()) {
|
| | return {};
|
| | }
|
| | item = &_SelStackBack[_SelStackForward.size() - 1 - index];
|
| | }
|
| |
|
| | std::list<_SelObj> selList;
|
| | for (auto& sobjT : *item) {
|
| | _SelObj sel;
|
| | if (checkSelection(
|
| | sobjT.getDocumentName().c_str(),
|
| | sobjT.getObjectName().c_str(),
|
| | sobjT.getSubName().c_str(),
|
| | ResolveMode::NoResolve,
|
| | sel,
|
| | &selList
|
| | )
|
| | == 0) {
|
| | selList.push_back(sel);
|
| | }
|
| | }
|
| |
|
| | return getObjectList(pDocName, App::DocumentObject::getClassTypeId(), selList, resolve);
|
| | }
|
| |
|
| | bool SelectionSingleton::addSelections(
|
| | const char* pDocName,
|
| | const char* pObjectName,
|
| | const std::vector<std::string>& pSubNames
|
| | )
|
| | {
|
| | if (!_PickedList.empty()) {
|
| | _PickedList.clear();
|
| | notify(SelectionChanges(SelectionChanges::PickedListChanged));
|
| | }
|
| |
|
| | bool update = false;
|
| | for (const auto& pSubName : pSubNames) {
|
| | _SelObj temp;
|
| | int ret = checkSelection(pDocName, pObjectName, pSubName.c_str(), ResolveMode::NoResolve, temp);
|
| | if (ret != 0) {
|
| | continue;
|
| | }
|
| |
|
| | temp.x = 0;
|
| | temp.y = 0;
|
| | temp.z = 0;
|
| |
|
| | _SelList.push_back(temp);
|
| | _SelStackForward.clear();
|
| |
|
| | SelectionChanges Chng(
|
| | SelectionChanges::AddSelection,
|
| | temp.DocName,
|
| | temp.FeatName,
|
| | temp.SubName,
|
| | temp.TypeName
|
| | );
|
| |
|
| | FC_LOG("Add Selection " << Chng.pDocName << '#' << Chng.pObjectName << '.' << Chng.pSubName);
|
| |
|
| | notify(std::move(Chng));
|
| | update = true;
|
| | }
|
| |
|
| | if (update) {
|
| | getMainWindow()->updateActions();
|
| | }
|
| | return true;
|
| | }
|
| |
|
| | bool SelectionSingleton::updateSelection(
|
| | bool show,
|
| | const char* pDocName,
|
| | const char* pObjectName,
|
| | const char* pSubName
|
| | )
|
| | {
|
| | if (!pDocName || !pObjectName) {
|
| | return false;
|
| | }
|
| | if (!pSubName) {
|
| | pSubName = "";
|
| | }
|
| | if (DocName == pDocName && FeatName == pObjectName && SubName == pSubName) {
|
| | if (show) {
|
| | FC_TRACE("preselect signal");
|
| | notify(SelectionChanges(SelectionChanges::SetPreselectSignal, DocName, FeatName, SubName));
|
| | }
|
| | else {
|
| | rmvPreselect();
|
| | }
|
| | }
|
| | auto pDoc = getDocument(pDocName);
|
| | if (!pDoc) {
|
| | return false;
|
| | }
|
| | auto pObject = pDoc->getObject(pObjectName);
|
| | if (!pObject) {
|
| | return false;
|
| | }
|
| | if (!isSelected(pObject, pSubName, ResolveMode::NoResolve)) {
|
| | return false;
|
| | }
|
| |
|
| | SelectionChanges Chng(
|
| | show ? SelectionChanges::ShowSelection : SelectionChanges::HideSelection,
|
| | pDocName,
|
| | pObjectName,
|
| | pSubName,
|
| | pObject->getTypeId().getName()
|
| | );
|
| |
|
| | FC_LOG("Update Selection " << Chng.pDocName << '#' << Chng.pObjectName << '.' << Chng.pSubName);
|
| |
|
| | notify(std::move(Chng));
|
| |
|
| | return true;
|
| | }
|
| |
|
| | bool SelectionSingleton::addSelection(const SelectionObject& obj, bool clearPreselect)
|
| | {
|
| | const std::vector<std::string>& subNames = obj.getSubNames();
|
| | const std::vector<Base::Vector3d> points = obj.getPickedPoints();
|
| | if (!subNames.empty() && subNames.size() == points.size()) {
|
| | bool ok = true;
|
| | for (std::size_t i = 0; i < subNames.size(); i++) {
|
| | const std::string& name = subNames[i];
|
| | const Base::Vector3d& pnt = points[i];
|
| | ok &= addSelection(
|
| | obj.getDocName(),
|
| | obj.getFeatName(),
|
| | name.c_str(),
|
| | static_cast<float>(pnt.x),
|
| | static_cast<float>(pnt.y),
|
| | static_cast<float>(pnt.z),
|
| | nullptr,
|
| | clearPreselect
|
| | );
|
| | }
|
| | return ok;
|
| | }
|
| | else if (!subNames.empty()) {
|
| | bool ok = true;
|
| | for (const std::string& name : subNames) {
|
| | ok &= addSelection(obj.getDocName(), obj.getFeatName(), name.c_str());
|
| | }
|
| | return ok;
|
| | }
|
| | else {
|
| | return addSelection(obj.getDocName(), obj.getFeatName());
|
| | }
|
| | }
|
| |
|
| |
|
| | void SelectionSingleton::rmvSelection(
|
| | const char* pDocName,
|
| | const char* pObjectName,
|
| | const char* pSubName,
|
| | const std::vector<SelObj>* pickedList
|
| | )
|
| | {
|
| | if (pickedList) {
|
| | _PickedList.clear();
|
| | for (const auto& sel : *pickedList) {
|
| | _PickedList.emplace_back();
|
| | auto& s = _PickedList.back();
|
| | s.DocName = sel.DocName;
|
| | s.FeatName = sel.FeatName;
|
| | s.SubName = sel.SubName;
|
| | s.TypeName = sel.TypeName;
|
| | s.pObject = sel.pObject;
|
| | s.pDoc = sel.pDoc;
|
| | s.x = sel.x;
|
| | s.y = sel.y;
|
| | s.z = sel.z;
|
| | }
|
| | notify(SelectionChanges(SelectionChanges::PickedListChanged));
|
| | }
|
| |
|
| | if (!pDocName) {
|
| | return;
|
| | }
|
| |
|
| | _SelObj temp;
|
| | int ret = checkSelection(pDocName, pObjectName, pSubName, ResolveMode::NoResolve, temp);
|
| | if (ret < 0) {
|
| | return;
|
| | }
|
| |
|
| | std::vector<SelectionChanges> changes;
|
| | for (auto It = _SelList.begin(), ItNext = It; It != _SelList.end(); It = ItNext) {
|
| | ++ItNext;
|
| | if (It->DocName != temp.DocName || It->FeatName != temp.FeatName) {
|
| | continue;
|
| | }
|
| |
|
| | if (!temp.SubName.empty()) {
|
| |
|
| | if (!boost::starts_with(It->SubName, temp.SubName)
|
| | || (It->SubName.length() != temp.SubName.length()
|
| | && It->SubName[temp.SubName.length() - 1] != '.')) {
|
| | continue;
|
| | }
|
| | }
|
| |
|
| | It->log(true);
|
| |
|
| | changes.emplace_back(
|
| | SelectionChanges::RmvSelection,
|
| | It->DocName,
|
| | It->FeatName,
|
| | It->SubName,
|
| | It->TypeName
|
| | );
|
| |
|
| |
|
| | _SelList.erase(It);
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | if (!changes.empty()) {
|
| | for (auto& Chng : changes) {
|
| | FC_LOG(
|
| | "Rmv Selection " << Chng.pDocName << '#' << Chng.pObjectName << '.' << Chng.pSubName
|
| | );
|
| | notify(std::move(Chng));
|
| | }
|
| | getMainWindow()->updateActions();
|
| | }
|
| | }
|
| |
|
| | struct SelInfo
|
| | {
|
| | std::string DocName;
|
| | std::string FeatName;
|
| | std::string SubName;
|
| | SelInfo(const std::string& docName, const std::string& featName, const std::string& subName)
|
| | : DocName(docName)
|
| | , FeatName(featName)
|
| | , SubName(subName)
|
| | {}
|
| | };
|
| |
|
| | void SelectionSingleton::setVisible(VisibleState vis)
|
| | {
|
| | std::set<std::pair<App::DocumentObject*, App::DocumentObject*>> filter;
|
| | int visible;
|
| | switch (vis) {
|
| | case VisShow:
|
| | visible = 1;
|
| | break;
|
| | case VisToggle:
|
| | visible = -1;
|
| | break;
|
| | default:
|
| | visible = 0;
|
| | }
|
| |
|
| |
|
| | std::vector<SelInfo> sels;
|
| | sels.reserve(_SelList.size());
|
| | for (auto& sel : _SelList) {
|
| | if (sel.DocName.empty() || sel.FeatName.empty() || !sel.pObject) {
|
| | continue;
|
| | }
|
| | sels.emplace_back(sel.DocName, sel.FeatName, sel.SubName);
|
| | }
|
| |
|
| | for (auto& sel : sels) {
|
| | App::Document* doc = App::GetApplication().getDocument(sel.DocName.c_str());
|
| | if (!doc) {
|
| | continue;
|
| | }
|
| | App::DocumentObject* obj = doc->getObject(sel.FeatName.c_str());
|
| | if (!obj) {
|
| | continue;
|
| | }
|
| |
|
| |
|
| | App::DocumentObject* parent = nullptr;
|
| | std::string elementName;
|
| | obj = obj->resolve(sel.SubName.c_str(), &parent, &elementName);
|
| | if (!obj || !obj->isAttachedToDocument() || (parent && !parent->isAttachedToDocument())) {
|
| | continue;
|
| | }
|
| |
|
| | if (parent) {
|
| |
|
| | if (!filter.insert(std::make_pair(obj, parent)).second) {
|
| | continue;
|
| | }
|
| | int visElement = parent->isElementVisible(elementName.c_str());
|
| | if (visElement >= 0) {
|
| | if (visElement > 0) {
|
| | visElement = 1;
|
| | }
|
| | if (visible >= 0) {
|
| | if (visElement == visible) {
|
| | continue;
|
| | }
|
| | visElement = visible;
|
| | }
|
| | else {
|
| | visElement = !visElement;
|
| | }
|
| |
|
| | if (!visElement) {
|
| | updateSelection(
|
| | false,
|
| | sel.DocName.c_str(),
|
| | sel.FeatName.c_str(),
|
| | sel.SubName.c_str()
|
| | );
|
| | }
|
| | parent->setElementVisible(elementName.c_str(), visElement ? true : false);
|
| | if (visElement) {
|
| | updateSelection(true, sel.DocName.c_str(), sel.FeatName.c_str(), sel.SubName.c_str());
|
| | }
|
| | continue;
|
| | }
|
| |
|
| |
|
| | }
|
| | if (!filter.insert(std::make_pair(obj, static_cast<App::DocumentObject*>(nullptr))).second) {
|
| | continue;
|
| | }
|
| |
|
| | auto vp = Application::Instance->getViewProvider(obj);
|
| |
|
| | if (vp) {
|
| | bool visObject;
|
| | if (visible >= 0) {
|
| | visObject = visible ? true : false;
|
| | }
|
| | else {
|
| | visObject = !vp->isShow();
|
| | }
|
| |
|
| | if (visObject) {
|
| | vp->show();
|
| | updateSelection(
|
| | visObject,
|
| | sel.DocName.c_str(),
|
| | sel.FeatName.c_str(),
|
| | sel.SubName.c_str()
|
| | );
|
| | }
|
| | else {
|
| | updateSelection(
|
| | visObject,
|
| | sel.DocName.c_str(),
|
| | sel.FeatName.c_str(),
|
| | sel.SubName.c_str()
|
| | );
|
| | vp->hide();
|
| | }
|
| | }
|
| | }
|
| | }
|
| |
|
| | void SelectionSingleton::setSelection(const char* pDocName, const std::vector<App::DocumentObject*>& sel)
|
| | {
|
| | App::Document* pcDoc;
|
| | pcDoc = getDocument(pDocName);
|
| | if (!pcDoc) {
|
| | return;
|
| | }
|
| |
|
| | if (!_PickedList.empty()) {
|
| | _PickedList.clear();
|
| | notify(SelectionChanges(SelectionChanges::PickedListChanged));
|
| | }
|
| |
|
| | bool touched = false;
|
| | for (auto obj : sel) {
|
| | if (!obj || !obj->isAttachedToDocument()) {
|
| | continue;
|
| | }
|
| | _SelObj temp;
|
| | int ret
|
| | = checkSelection(pDocName, obj->getNameInDocument(), nullptr, ResolveMode::NoResolve, temp);
|
| | if (ret != 0) {
|
| | continue;
|
| | }
|
| | touched = true;
|
| | _SelList.push_back(temp);
|
| | }
|
| |
|
| | if (touched) {
|
| | _SelStackForward.clear();
|
| | notify(SelectionChanges(SelectionChanges::SetSelection, pDocName));
|
| | getMainWindow()->updateActions();
|
| | }
|
| | }
|
| |
|
| | void SelectionSingleton::clearSelection(const char* pDocName, bool clearPreSelect)
|
| | {
|
| |
|
| |
|
| |
|
| | if (!pDocName || !pDocName[0] || strcmp(pDocName, "*") == 0) {
|
| | clearCompleteSelection(clearPreSelect);
|
| | return;
|
| | }
|
| |
|
| | if (!_PickedList.empty()) {
|
| | _PickedList.clear();
|
| | notify(SelectionChanges(SelectionChanges::PickedListChanged));
|
| | }
|
| |
|
| | App::Document* pDoc;
|
| | pDoc = getDocument(pDocName);
|
| | if (pDoc) {
|
| | std::string docName = pDocName;
|
| | if (clearPreSelect && DocName == docName) {
|
| | rmvPreselect();
|
| | }
|
| |
|
| | bool touched = false;
|
| | for (auto it = _SelList.begin(); it != _SelList.end();) {
|
| | if (it->DocName == docName) {
|
| | touched = true;
|
| | it = _SelList.erase(it);
|
| | }
|
| | else {
|
| | ++it;
|
| | }
|
| | }
|
| |
|
| | if (!touched) {
|
| | return;
|
| | }
|
| |
|
| | if (!logDisabled) {
|
| | std::ostringstream ss;
|
| | ss << "Gui.Selection.clearSelection('" << docName << "'";
|
| | if (!clearPreSelect) {
|
| | ss << ", False";
|
| | }
|
| | ss << ')';
|
| | Application::Instance->macroManager()->addLine(MacroManager::Cmt, ss.str().c_str());
|
| | }
|
| |
|
| | notify(SelectionChanges(SelectionChanges::ClrSelection, docName.c_str()));
|
| |
|
| | getMainWindow()->updateActions();
|
| | }
|
| | }
|
| |
|
| | void SelectionSingleton::clearCompleteSelection(bool clearPreSelect)
|
| | {
|
| | if (!_PickedList.empty()) {
|
| | _PickedList.clear();
|
| | notify(SelectionChanges(SelectionChanges::PickedListChanged));
|
| | }
|
| |
|
| | if (clearPreSelect) {
|
| | rmvPreselect();
|
| | }
|
| |
|
| | if (_SelList.empty()) {
|
| | return;
|
| | }
|
| |
|
| | if (!logDisabled) {
|
| | Application::Instance->macroManager()->addLine(
|
| | MacroManager::Cmt,
|
| | clearPreSelect ? "Gui.Selection.clearSelection()" : "Gui.Selection.clearSelection(False)"
|
| | );
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| | std::set<ViewProvider*> viewProviders;
|
| | for (_SelObj& sel : _SelList) {
|
| | if (auto vp = Application::Instance->getViewProvider(sel.pObject)) {
|
| | viewProviders.insert(vp);
|
| | }
|
| | }
|
| |
|
| | for (auto& vp : viewProviders) {
|
| | SelectionChanges Chng(SelectionChanges::ClrSelection);
|
| | vp->onSelectionChanged(Chng);
|
| | }
|
| |
|
| | _SelList.clear();
|
| |
|
| | SelectionChanges Chng(SelectionChanges::ClrSelection);
|
| |
|
| | FC_LOG("Clear selection");
|
| |
|
| | notify(std::move(Chng));
|
| | getMainWindow()->updateActions();
|
| | }
|
| |
|
| | bool SelectionSingleton::isSelected(
|
| | const char* pDocName,
|
| | const char* pObjectName,
|
| | const char* pSubName,
|
| | ResolveMode resolve
|
| | ) const
|
| | {
|
| | _SelObj sel;
|
| | return checkSelection(pDocName, pObjectName, pSubName, resolve, sel, &_SelList) > 0;
|
| | }
|
| |
|
| | bool SelectionSingleton::isSelected(
|
| | App::DocumentObject* pObject,
|
| | const char* pSubName,
|
| | ResolveMode resolve
|
| | ) const
|
| | {
|
| | if (!pObject || !pObject->isAttachedToDocument() || !pObject->getDocument()) {
|
| | return false;
|
| | }
|
| | _SelObj sel;
|
| | return checkSelection(
|
| | pObject->getDocument()->getName(),
|
| | pObject->getNameInDocument(),
|
| | pSubName,
|
| | resolve,
|
| | sel,
|
| | &_SelList
|
| | )
|
| | > 0;
|
| | }
|
| |
|
| | int SelectionSingleton::checkSelection(
|
| | const char* pDocName,
|
| | const char* pObjectName,
|
| | const char* pSubName,
|
| | ResolveMode resolve,
|
| | _SelObj& sel,
|
| | const std::list<_SelObj>* selList
|
| | ) const
|
| | {
|
| | sel.pDoc = getDocument(pDocName);
|
| | if (!sel.pDoc) {
|
| | if (!selList) {
|
| | FC_ERR("Cannot find document");
|
| | }
|
| | return -1;
|
| | }
|
| | pDocName = sel.pDoc->getName();
|
| | sel.DocName = pDocName;
|
| |
|
| | if (pObjectName) {
|
| | sel.pObject = sel.pDoc->getObject(pObjectName);
|
| | }
|
| | else {
|
| | sel.pObject = nullptr;
|
| | }
|
| | if (!sel.pObject) {
|
| | if (!selList) {
|
| | FC_ERR("Object not found");
|
| | }
|
| | return -1;
|
| | }
|
| | if (sel.pObject->testStatus(App::ObjectStatus::Remove)) {
|
| | return -1;
|
| | }
|
| | if (pSubName) {
|
| | sel.SubName = pSubName;
|
| | }
|
| | if (resolve == ResolveMode::NoResolve) {
|
| | TreeWidget::checkTopParent(sel.pObject, sel.SubName);
|
| | }
|
| | pSubName = !sel.SubName.empty() ? sel.SubName.c_str() : nullptr;
|
| | sel.FeatName = sel.pObject->getNameInDocument();
|
| | sel.TypeName = sel.pObject->getTypeId().getName();
|
| | const char* element = nullptr;
|
| | sel.pResolvedObject = App::GeoFeature::resolveElement(
|
| | sel.pObject,
|
| | pSubName,
|
| | sel.elementName,
|
| | false,
|
| | App::GeoFeature::Normal,
|
| | nullptr,
|
| | &element
|
| | );
|
| | if (!sel.pResolvedObject) {
|
| | if (!selList) {
|
| | FC_ERR(
|
| | "Sub-object " << sel.DocName << '#' << sel.FeatName << '.' << sel.SubName << " not found"
|
| | );
|
| | }
|
| | return -1;
|
| | }
|
| | if (sel.pResolvedObject->testStatus(App::ObjectStatus::Remove)) {
|
| | return -1;
|
| | }
|
| | std::string subname;
|
| | std::string prefix;
|
| | if (pSubName && element) {
|
| | prefix = std::string(pSubName, element - pSubName);
|
| | if (!sel.elementName.newName.empty()) {
|
| |
|
| | subname = prefix + sel.elementName.newName;
|
| | pSubName = subname.c_str();
|
| | sel.SubName = subname;
|
| | }
|
| | }
|
| | if (!selList) {
|
| | selList = &_SelList;
|
| | }
|
| |
|
| | if (!pSubName) {
|
| | pSubName = "";
|
| | }
|
| |
|
| | for (auto& s : *selList) {
|
| | if (s.DocName == pDocName && s.FeatName == sel.FeatName) {
|
| | if (s.SubName == pSubName) {
|
| | return 1;
|
| | }
|
| | if (resolve > ResolveMode::OldStyleElement && boost::starts_with(s.SubName, prefix)) {
|
| | return 1;
|
| | }
|
| | }
|
| | }
|
| | if (resolve == ResolveMode::OldStyleElement) {
|
| | for (auto& s : *selList) {
|
| | if (s.pResolvedObject != sel.pResolvedObject) {
|
| | continue;
|
| | }
|
| | if (!pSubName[0]) {
|
| | return 1;
|
| | }
|
| | if (!s.elementName.newName.empty()) {
|
| | if (s.elementName.newName == sel.elementName.newName) {
|
| | return 1;
|
| | }
|
| | }
|
| | else if (s.SubName == sel.elementName.oldName) {
|
| | return 1;
|
| | }
|
| | }
|
| | }
|
| | return 0;
|
| | }
|
| |
|
| | const char* SelectionSingleton::getSelectedElement(App::DocumentObject* obj, const char* pSubName) const
|
| | {
|
| | if (!obj) {
|
| | return nullptr;
|
| | }
|
| |
|
| | for (list<_SelObj>::const_iterator It = _SelList.begin(); It != _SelList.end(); ++It) {
|
| | if (It->pObject == obj) {
|
| | auto len = It->SubName.length();
|
| | if (!len) {
|
| | return "";
|
| | }
|
| | if (pSubName && strncmp(pSubName, It->SubName.c_str(), It->SubName.length()) == 0) {
|
| | if (pSubName[len] == 0 || pSubName[len - 1] == '.') {
|
| | return It->SubName.c_str();
|
| | }
|
| | }
|
| | }
|
| | }
|
| | return nullptr;
|
| | }
|
| |
|
| | void SelectionSingleton::slotDeletedObject(const App::DocumentObject& Obj)
|
| | {
|
| | if (!Obj.isAttachedToDocument()) {
|
| | return;
|
| | }
|
| |
|
| |
|
| | rmvPreselect();
|
| |
|
| |
|
| |
|
| | std::vector<SelectionChanges> changes;
|
| | for (auto it = _SelList.begin(), itNext = it; it != _SelList.end(); it = itNext) {
|
| | ++itNext;
|
| | if (it->pResolvedObject == &Obj || it->pObject == &Obj) {
|
| | changes.emplace_back(
|
| | SelectionChanges::RmvSelection,
|
| | it->DocName,
|
| | it->FeatName,
|
| | it->SubName,
|
| | it->TypeName
|
| | );
|
| | _SelList.erase(it);
|
| | }
|
| | }
|
| | if (!changes.empty()) {
|
| | for (auto& Chng : changes) {
|
| | FC_LOG(
|
| | "Rmv Selection " << Chng.pDocName << '#' << Chng.pObjectName << '.' << Chng.pSubName
|
| | );
|
| | notify(std::move(Chng));
|
| | }
|
| | getMainWindow()->updateActions();
|
| | }
|
| |
|
| | if (!_PickedList.empty()) {
|
| | bool changed = false;
|
| | for (auto it = _PickedList.begin(), itNext = it; it != _PickedList.end(); it = itNext) {
|
| | ++itNext;
|
| | auto& sel = *it;
|
| | if (sel.DocName == Obj.getDocument()->getName()
|
| | && sel.FeatName == Obj.getNameInDocument()) {
|
| | changed = true;
|
| | _PickedList.erase(it);
|
| | }
|
| | }
|
| | if (changed) {
|
| | notify(SelectionChanges(SelectionChanges::PickedListChanged));
|
| | }
|
| | }
|
| | }
|
| |
|
| | void SelectionSingleton::setSelectionStyle(SelectionStyle selStyle)
|
| | {
|
| | selectionStyle = selStyle;
|
| | }
|
| |
|
| | SelectionSingleton::SelectionStyle SelectionSingleton::getSelectionStyle()
|
| | {
|
| | return selectionStyle;
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| | |
| | |
| | |
| |
|
| | SelectionSingleton::SelectionSingleton()
|
| | : CurrentPreselection(SelectionChanges::ClrSelection)
|
| | , selectionStyle(SelectionStyle::NormalSelection)
|
| | {
|
| | hx = 0;
|
| | hy = 0;
|
| | hz = 0;
|
| | ActiveGate = nullptr;
|
| | gateResolve = ResolveMode::OldStyleElement;
|
| |
|
| | App::GetApplication().signalDeletedObject.connect(
|
| | std::bind(&Gui::SelectionSingleton::slotDeletedObject, this, sp::_1)
|
| | );
|
| | signalSelectionChanged.connect(
|
| | std::bind(&Gui::SelectionSingleton::slotSelectionChanged, this, sp::_1)
|
| | );
|
| |
|
| | }
|
| |
|
| | |
| | |
| | |
| |
|
| | SelectionSingleton::~SelectionSingleton() = default;
|
| |
|
| | SelectionSingleton* SelectionSingleton::_pcSingleton = nullptr;
|
| |
|
| | SelectionSingleton& SelectionSingleton::instance()
|
| | {
|
| | if (!_pcSingleton) {
|
| | _pcSingleton = new SelectionSingleton;
|
| | }
|
| | return *_pcSingleton;
|
| | }
|
| |
|
| | void SelectionSingleton::destruct()
|
| | {
|
| | if (_pcSingleton) {
|
| | delete _pcSingleton;
|
| | }
|
| | _pcSingleton = nullptr;
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | PyMethodDef SelectionSingleton::Methods[] = {
|
| | {"addSelection",
|
| | (PyCFunction)SelectionSingleton::sAddSelection,
|
| | METH_VARARGS,
|
| | "addSelection(docName, objName, subName, x=0, y=0, z=0, clear=True) -> None\n"
|
| | "addSelection(obj, subName, x=0, y=0, z=0, clear=True) -> None\n"
|
| | "addSelection(obj, subNames, clear=True) -> None\n"
|
| | "\n"
|
| | "Add an object to the selection.\n"
|
| | "\n"
|
| | "docName : str\n Name of the `App.Document`.\n"
|
| | "objName : str\n Name of the `App.DocumentObject` to add.\n"
|
| | "obj : App.DocumentObject\n Object to add.\n"
|
| | "subName : str\n Subelement name.\n"
|
| | "x : float\n Coordinate `x` of the point to pick.\n"
|
| | "y : float\n Coordinate `y` of the point to pick.\n"
|
| | "z : float\n Coordinate `z` of the point to pick.\n"
|
| | "subNames : list of str\n List of subelement names.\n"
|
| | "clear : bool\n Clear preselection."},
|
| | {"updateSelection",
|
| | (PyCFunction)SelectionSingleton::sUpdateSelection,
|
| | METH_VARARGS,
|
| | "updateSelection(show, obj, subName) -> None\n"
|
| | "\n"
|
| | "Update an object in the selection.\n"
|
| | "\n"
|
| | "show : bool\n Show or hide the selection.\n"
|
| | "obj : App.DocumentObject\n Object to update.\n"
|
| | "subName : str\n Name of the subelement to update."},
|
| | {"removeSelection",
|
| | (PyCFunction)SelectionSingleton::sRemoveSelection,
|
| | METH_VARARGS,
|
| | "removeSelection(obj, subName) -> None\n"
|
| | "removeSelection(docName, objName, subName) -> None\n"
|
| | "\n"
|
| | "Remove an object from the selection.\n"
|
| | "\n"
|
| | "docName : str\n Name of the `App.Document`.\n"
|
| | "objName : str\n Name of the `App.DocumentObject` to remove.\n"
|
| | "obj : App.DocumentObject\n Object to remove.\n"
|
| | "subName : str\n Name of the subelement to remove."},
|
| | {"clearSelection",
|
| | (PyCFunction)SelectionSingleton::sClearSelection,
|
| | METH_VARARGS,
|
| | "clearSelection(docName, clearPreSelect=True) -> None\n"
|
| | "clearSelection(clearPreSelect=True) -> None\n"
|
| | "\n"
|
| | "Clear the selection in the given document. If no document is\n"
|
| | "given the complete selection is cleared.\n"
|
| | "\n"
|
| | "docName : str\n Name of the `App.Document`.\n"
|
| | "clearPreSelect : bool\n Clear preselection."},
|
| | {"isSelected",
|
| | (PyCFunction)SelectionSingleton::sIsSelected,
|
| | METH_VARARGS,
|
| | "isSelected(obj, subName, resolve=ResolveMode.OldStyleElement) -> bool\n"
|
| | "\n"
|
| | "Check if a given object is selected.\n"
|
| | "\n"
|
| | "obj : App.DocumentObject\n Object to check.\n"
|
| | "subName : str\n Name of the subelement.\n"
|
| | "resolve : int\n Resolve subelement reference."},
|
| | {"setPreselection",
|
| | reinterpret_cast<PyCFunction>(reinterpret_cast<void (*)()>(SelectionSingleton::sSetPreselection)),
|
| | METH_VARARGS | METH_KEYWORDS,
|
| | "setPreselection(obj, subName, x=0, y=0, z=0, type=1) -> None\n"
|
| | "\n"
|
| | "Set preselected object.\n"
|
| | "\n"
|
| | "obj : App.DocumentObject\n Object to preselect.\n"
|
| | "subName : str\n Subelement name.\n"
|
| | "x : float\n Coordinate `x` of the point to preselect.\n"
|
| | "y : float\n Coordinate `y` of the point to preselect.\n"
|
| | "z : float\n Coordinate `z` of the point to preselect.\n"
|
| | "type : int"},
|
| | {"getPreselection",
|
| | (PyCFunction)SelectionSingleton::sGetPreselection,
|
| | METH_VARARGS,
|
| | "getPreselection() -> Gui.SelectionObject\n"
|
| | "\n"
|
| | "Get preselected object."},
|
| | {"clearPreselection",
|
| | (PyCFunction)SelectionSingleton::sRemPreselection,
|
| | METH_VARARGS,
|
| | "clearPreselection() -> None\n"
|
| | "\n"
|
| | "Clear the preselection."},
|
| | {"countObjectsOfType",
|
| | (PyCFunction)SelectionSingleton::sCountObjectsOfType,
|
| | METH_VARARGS,
|
| | "countObjectsOfType(type, docName, resolve=ResolveMode.OldStyleElement) -> int\n"
|
| | "\n"
|
| | "Get the number of selected objects. If no document name is given the\n"
|
| | "active document is used and '*' means all documents.\n"
|
| | "\n"
|
| | "type : str\n Object type id name.\n"
|
| | "docName : str\n Name of the `App.Document`.\n"
|
| | "resolve : int"},
|
| | {"getSelection",
|
| | (PyCFunction)SelectionSingleton::sGetSelection,
|
| | METH_VARARGS,
|
| | "getSelection(docName, resolve=ResolveMode.OldStyleElement, single=False) -> list\n"
|
| | "\n"
|
| | "Return a list of selected objects. If no document name is given\n"
|
| | "the active document is used and '*' means all documents.\n"
|
| | "\n"
|
| | "docName : str\n Name of the `App.Document`.\n"
|
| | "resolve : int\n Resolve the subname references.\n"
|
| | " 0: do not resolve, 1: resolve, 2: resolve with element map.\n"
|
| | "single : bool\n Only return if there is only one selection."},
|
| | {"getPickedList",
|
| | (PyCFunction)SelectionSingleton::sGetPickedList,
|
| | 1,
|
| | "getPickedList(docName) -> list of Gui.SelectionObject\n"
|
| | "\n"
|
| | "Return a list of SelectionObjects generated by the last mouse click.\n"
|
| | "If no document name is given the active document is used and '*'\n"
|
| | "means all documents.\n"
|
| | "\n"
|
| | "docName : str\n Name of the `App.Document`."},
|
| | {"enablePickedList",
|
| | (PyCFunction)SelectionSingleton::sEnablePickedList,
|
| | METH_VARARGS,
|
| | "enablePickedList(enable=True) -> None\n"
|
| | "\n"
|
| | "Enable/disable pick list.\n"
|
| | "\n"
|
| | "enable : bool"},
|
| | {"getCompleteSelection",
|
| | (PyCFunction)SelectionSingleton::sGetCompleteSelection,
|
| | METH_VARARGS,
|
| | "getCompleteSelection(resolve=ResolveMode.OldStyleElement) -> list\n"
|
| | "\n"
|
| | "Return a list of selected objects across all documents.\n"
|
| | "\n"
|
| | "resolve : int"},
|
| | {"getSelectionEx",
|
| | (PyCFunction)SelectionSingleton::sGetSelectionEx,
|
| | METH_VARARGS,
|
| | "getSelectionEx(docName, resolve=ResolveMode.OldStyleElement, single=False) -> list of "
|
| | "Gui.SelectionObject\n"
|
| | "\n"
|
| | "Return a list of SelectionObjects. If no document name is given the\n"
|
| | "active document is used and '*' means all documents.\n"
|
| | "The SelectionObjects contain a variety of information about the selection,\n"
|
| | "e.g. subelement names.\n"
|
| | "\n"
|
| | "docName : str\n Name of the `App.Document`.\n"
|
| | "resolve : int\n Resolve the subname references.\n"
|
| | " 0: do not resolve, 1: resolve, 2: resolve with element map.\n"
|
| | "single : bool\n Only return if there is only one selection."},
|
| | {"getSelectionObject",
|
| | (PyCFunction)SelectionSingleton::sGetSelectionObject,
|
| | METH_VARARGS,
|
| | "getSelectionObject(docName, objName, subName, point) -> Gui.SelectionObject\n"
|
| | "\n"
|
| | "Return a SelectionObject.\n"
|
| | "\n"
|
| | "docName : str\n Name of the `App.Document`.\n"
|
| | "objName : str\n Name of the `App.DocumentObject` to select.\n"
|
| | "subName : str\n Subelement name.\n"
|
| | "point : tuple\n Coordinates of the point to pick."},
|
| | {"setSelectionStyle",
|
| | (PyCFunction)SelectionSingleton::sSetSelectionStyle,
|
| | METH_VARARGS,
|
| | "setSelectionStyle(selectionStyle) -> None\n"
|
| | "\n"
|
| | "Change the selection style. 0 for normal selection, 1 for greedy selection\n"
|
| | "\n"
|
| | "selectionStyle : int"},
|
| | {"addObserver",
|
| | (PyCFunction)SelectionSingleton::sAddSelObserver,
|
| | METH_VARARGS,
|
| | "addObserver(object, resolve=ResolveMode.OldStyleElement) -> None\n"
|
| | "\n"
|
| | "Install an observer.\n"
|
| | "\n"
|
| | "object : object\n Python object instance.\n"
|
| | "resolve : int"},
|
| | {"removeObserver",
|
| | (PyCFunction)SelectionSingleton::sRemSelObserver,
|
| | METH_VARARGS,
|
| | "removeObserver(object) -> None\n"
|
| | "\n"
|
| | "Uninstall an observer.\n"
|
| | "\n"
|
| | "object : object\n Python object instance."},
|
| | {"addSelectionGate",
|
| | (PyCFunction)SelectionSingleton::sAddSelectionGate,
|
| | METH_VARARGS,
|
| | "addSelectionGate(filter, resolve=ResolveMode.OldStyleElement) -> None\n"
|
| | "\n"
|
| | "Activate the selection gate.\n"
|
| | "The selection gate will prohibit all selections that do not match\n"
|
| | "the given selection criteria.\n"
|
| | "\n"
|
| | "filter : str, SelectionFilter, object\n"
|
| | "resolve : int\n"
|
| | "\n"
|
| | "Examples strings are:\n"
|
| | "Gui.Selection.addSelectionGate('SELECT Part::Feature SUBELEMENT Edge')\n"
|
| | "Gui.Selection.addSelectionGate('SELECT Robot::RobotObject')\n"
|
| | "\n"
|
| | "An instance of SelectionFilter can also be set:\n"
|
| | "filter = Gui.Selection.Filter('SELECT Part::Feature SUBELEMENT Edge')\n"
|
| | "Gui.Selection.addSelectionGate(filter)\n"
|
| | "\n"
|
| | "The most flexible approach is to write a selection gate class that\n"
|
| | "implements the method 'allow':\n"
|
| | "class Gate:\n"
|
| | " def allow(self,doc,obj,sub):\n"
|
| | " return (sub[0:4] == 'Face')\n"
|
| | "Gui.Selection.addSelectionGate(Gate())"},
|
| | {"removeSelectionGate",
|
| | (PyCFunction)SelectionSingleton::sRemoveSelectionGate,
|
| | METH_VARARGS,
|
| | "removeSelectionGate() -> None\n"
|
| | "\n"
|
| | "Remove the active selection gate."},
|
| | {"setVisible",
|
| | (PyCFunction)SelectionSingleton::sSetVisible,
|
| | METH_VARARGS,
|
| | "setVisible(visible=None) -> None\n"
|
| | "\n"
|
| | "Set visibility of all selection items.\n"
|
| | "\n"
|
| | "visible : bool, None\n If None, then toggle visibility."},
|
| | {"pushSelStack",
|
| | (PyCFunction)SelectionSingleton::sPushSelStack,
|
| | METH_VARARGS,
|
| | "pushSelStack(clearForward=True, overwrite=False) -> None\n"
|
| | "\n"
|
| | "Push current selection to stack.\n"
|
| | "\n"
|
| | "clearForward : bool\n Clear the forward selection stack.\n"
|
| | "overwrite : bool\n Overwrite the top back selection stack with current selection."},
|
| | {"hasSelection",
|
| | (PyCFunction)SelectionSingleton::sHasSelection,
|
| | METH_VARARGS,
|
| | "hasSelection(docName, resolve=ResolveMode.NoResolve) -> bool\n"
|
| | "\n"
|
| | "Check if there is any selection. If no document name is given,\n"
|
| | "checks selections in all documents.\n"
|
| | "\n"
|
| | "docName : str\n Name of the `App.Document`.\n"
|
| | "resolve : int"},
|
| | {"hasSubSelection",
|
| | (PyCFunction)SelectionSingleton::sHasSubSelection,
|
| | METH_VARARGS,
|
| | "hasSubSelection(docName, subElement=False) -> bool\n"
|
| | "\n"
|
| | "Check if there is any selection with subname. If no document name\n"
|
| | "is given the active document is used and '*' means all documents.\n"
|
| | "\n"
|
| | "docName : str\n Name of the `App.Document`.\n"
|
| | "subElement : bool"},
|
| | {"getSelectionFromStack",
|
| | (PyCFunction)SelectionSingleton::sGetSelectionFromStack,
|
| | METH_VARARGS,
|
| | "getSelectionFromStack(docName, resolve=ResolveMode.OldStyleElement, index=0) -> list of "
|
| | "Gui.SelectionObject\n"
|
| | "\n"
|
| | "Return SelectionObjects from selection stack. If no document name is given\n"
|
| | "the active document is used and '*' means all documents.\n"
|
| | "\n"
|
| | "docName : str\n Name of the `App.Document`.\n"
|
| | "resolve : int\n Resolve the subname references.\n"
|
| | " 0: do not resolve, 1: resolve, 2: resolve with element map.\n"
|
| | "index : int\n Select stack index.\n"
|
| | " 0: last pushed selection, > 0: trace back, < 0: trace forward."},
|
| | {nullptr, nullptr, 0, nullptr}
|
| | };
|
| |
|
| | PyObject* SelectionSingleton::sAddSelection(PyObject* , PyObject* args)
|
| | {
|
| | SelectionLogDisabler disabler(true);
|
| | PyObject* clearPreselect = Py_True;
|
| | char* objname;
|
| | char* docname;
|
| | char* subname = nullptr;
|
| | float x = 0, y = 0, z = 0;
|
| | if (PyArg_ParseTuple(args, "ss|sfffO!", &docname, &objname, &subname, &x, &y, &z, &PyBool_Type, &clearPreselect)) {
|
| | Selection()
|
| | .addSelection(docname, objname, subname, x, y, z, nullptr, Base::asBoolean(clearPreselect));
|
| | Py_Return;
|
| | }
|
| |
|
| | PyErr_Clear();
|
| | PyObject* object;
|
| | subname = nullptr;
|
| | x = 0, y = 0, z = 0;
|
| | if (PyArg_ParseTuple(
|
| | args,
|
| | "O!|sfffO!",
|
| | &(App::DocumentObjectPy::Type),
|
| | &object,
|
| | &subname,
|
| | &x,
|
| | &y,
|
| | &z,
|
| | &PyBool_Type,
|
| | &clearPreselect
|
| | )) {
|
| | auto docObjPy = static_cast<App::DocumentObjectPy*>(object);
|
| | App::DocumentObject* docObj = docObjPy->getDocumentObjectPtr();
|
| | if (!docObj || !docObj->isAttachedToDocument()) {
|
| | PyErr_SetString(Base::PyExc_FC_GeneralError, "Cannot check invalid object");
|
| | return nullptr;
|
| | }
|
| |
|
| | Selection().addSelection(
|
| | docObj->getDocument()->getName(),
|
| | docObj->getNameInDocument(),
|
| | subname,
|
| | x,
|
| | y,
|
| | z,
|
| | nullptr,
|
| | Base::asBoolean(clearPreselect)
|
| | );
|
| | Py_Return;
|
| | }
|
| |
|
| | PyErr_Clear();
|
| | PyObject* sequence;
|
| | if (PyArg_ParseTuple(
|
| | args,
|
| | "O!O|O!",
|
| | &(App::DocumentObjectPy::Type),
|
| | &object,
|
| | &sequence,
|
| | &PyBool_Type,
|
| | &clearPreselect
|
| | )) {
|
| | auto docObjPy = static_cast<App::DocumentObjectPy*>(object);
|
| | App::DocumentObject* docObj = docObjPy->getDocumentObjectPtr();
|
| | if (!docObj || !docObj->isAttachedToDocument()) {
|
| | PyErr_SetString(Base::PyExc_FC_GeneralError, "Cannot check invalid object");
|
| | return nullptr;
|
| | }
|
| |
|
| | try {
|
| | if (PyTuple_Check(sequence) || PyList_Check(sequence)) {
|
| | Py::Sequence list(sequence);
|
| | for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
| | std::string subname = static_cast<std::string>(Py::String(*it));
|
| | Selection().addSelection(
|
| | docObj->getDocument()->getName(),
|
| | docObj->getNameInDocument(),
|
| | subname.c_str(),
|
| | 0,
|
| | 0,
|
| | 0,
|
| | nullptr,
|
| | Base::asBoolean(clearPreselect)
|
| | );
|
| | }
|
| | Py_Return;
|
| | }
|
| | }
|
| | catch (const Py::Exception&) {
|
| |
|
| | }
|
| | }
|
| |
|
| | PyErr_SetString(PyExc_ValueError, "type must be 'DocumentObject[,subname[,x,y,z]]' or 'DocumentObject, list or tuple of subnames'");
|
| |
|
| | return nullptr;
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sUpdateSelection(PyObject* , PyObject* args)
|
| | {
|
| | PyObject* show;
|
| | PyObject* object;
|
| | char* subname = nullptr;
|
| | if (!PyArg_ParseTuple(
|
| | args,
|
| | "O!O!|s",
|
| | &PyBool_Type,
|
| | &show,
|
| | &(App::DocumentObjectPy::Type),
|
| | &object,
|
| | &subname
|
| | )) {
|
| | return nullptr;
|
| | }
|
| |
|
| | auto docObjPy = static_cast<App::DocumentObjectPy*>(object);
|
| | App::DocumentObject* docObj = docObjPy->getDocumentObjectPtr();
|
| | if (!docObj || !docObj->isAttachedToDocument()) {
|
| | PyErr_SetString(Base::PyExc_FC_GeneralError, "Cannot check invalid object");
|
| | return nullptr;
|
| | }
|
| |
|
| | Selection().updateSelection(
|
| | Base::asBoolean(show),
|
| | docObj->getDocument()->getName(),
|
| | docObj->getNameInDocument(),
|
| | subname
|
| | );
|
| |
|
| | Py_Return;
|
| | }
|
| |
|
| |
|
| | PyObject* SelectionSingleton::sRemoveSelection(PyObject* , PyObject* args)
|
| | {
|
| | SelectionLogDisabler disabler(true);
|
| | char *docname, *objname;
|
| | char* subname = nullptr;
|
| | if (PyArg_ParseTuple(args, "ss|s", &docname, &objname, &subname)) {
|
| | Selection().rmvSelection(docname, objname, subname);
|
| | Py_Return;
|
| | }
|
| |
|
| | PyErr_Clear();
|
| | PyObject* object;
|
| | subname = nullptr;
|
| | if (!PyArg_ParseTuple(args, "O!|s", &(App::DocumentObjectPy::Type), &object, &subname)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | auto docObjPy = static_cast<App::DocumentObjectPy*>(object);
|
| | App::DocumentObject* docObj = docObjPy->getDocumentObjectPtr();
|
| | if (!docObj || !docObj->isAttachedToDocument()) {
|
| | PyErr_SetString(Base::PyExc_FC_GeneralError, "Cannot check invalid object");
|
| | return nullptr;
|
| | }
|
| |
|
| | Selection().rmvSelection(docObj->getDocument()->getName(), docObj->getNameInDocument(), subname);
|
| |
|
| | Py_Return;
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sClearSelection(PyObject* , PyObject* args)
|
| | {
|
| | SelectionLogDisabler disabler(true);
|
| | PyObject* clearPreSelect = Py_True;
|
| | char* documentName = nullptr;
|
| | if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &clearPreSelect)) {
|
| | PyErr_Clear();
|
| | if (!PyArg_ParseTuple(args, "|sO!", &documentName, &PyBool_Type, &clearPreSelect)) {
|
| | return nullptr;
|
| | }
|
| | }
|
| | Selection().clearSelection(documentName, Base::asBoolean(clearPreSelect));
|
| |
|
| | Py_Return;
|
| | }
|
| |
|
| | namespace
|
| | {
|
| | ResolveMode toEnum(int value)
|
| | {
|
| | switch (value) {
|
| | case 0:
|
| | return ResolveMode::NoResolve;
|
| | case 1:
|
| | return ResolveMode::OldStyleElement;
|
| | case 2:
|
| | return ResolveMode::NewStyleElement;
|
| | case 3:
|
| | return ResolveMode::FollowLink;
|
| | default:
|
| | throw Base::ValueError("Wrong enum value");
|
| | }
|
| | }
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sIsSelected(PyObject* , PyObject* args)
|
| | {
|
| | PyObject* object;
|
| | char* subname = nullptr;
|
| | int resolve = 1;
|
| | if (!PyArg_ParseTuple(args, "O!|si", &(App::DocumentObjectPy::Type), &object, &subname, &resolve)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | try {
|
| | auto docObj = static_cast<App::DocumentObjectPy*>(object);
|
| | bool ok = Selection().isSelected(docObj->getDocumentObjectPtr(), subname, toEnum(resolve));
|
| |
|
| | return Py_BuildValue("O", (ok ? Py_True : Py_False));
|
| | }
|
| | catch (const Base::Exception& e) {
|
| | e.setPyException();
|
| | return nullptr;
|
| | }
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sCountObjectsOfType(PyObject* , PyObject* args)
|
| | {
|
| | char* objecttype;
|
| | char* document = nullptr;
|
| | int resolve = 1;
|
| | if (!PyArg_ParseTuple(args, "s|si", &objecttype, &document, &resolve)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | try {
|
| | unsigned int count = Selection().countObjectsOfType(objecttype, document, toEnum(resolve));
|
| | return PyLong_FromLong(count);
|
| | }
|
| | catch (const Base::Exception& e) {
|
| | e.setPyException();
|
| | return nullptr;
|
| | }
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sGetSelection(PyObject* , PyObject* args)
|
| | {
|
| | char* documentName = nullptr;
|
| | int resolve = 1;
|
| | PyObject* single = Py_False;
|
| | if (!PyArg_ParseTuple(args, "|siO!", &documentName, &resolve, &PyBool_Type, &single)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | try {
|
| | std::vector<SelectionSingleton::SelObj> sel;
|
| | sel = Selection().getSelection(documentName, toEnum(resolve), Base::asBoolean(single));
|
| |
|
| | std::set<App::DocumentObject*> noduplicates;
|
| | std::vector<App::DocumentObject*> selectedObjects;
|
| | Py::List list;
|
| | for (const auto& it : sel) {
|
| | if (noduplicates.insert(it.pObject).second) {
|
| | selectedObjects.push_back(it.pObject);
|
| | }
|
| | }
|
| | for (const auto& selectedObject : selectedObjects) {
|
| | list.append(Py::asObject(selectedObject->getPyObject()));
|
| | }
|
| | return Py::new_reference_to(list);
|
| | }
|
| | catch (const Base::Exception& e) {
|
| | e.setPyException();
|
| | return nullptr;
|
| | }
|
| | catch (Py::Exception&) {
|
| | return nullptr;
|
| | }
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sEnablePickedList(PyObject* , PyObject* args)
|
| | {
|
| | PyObject* enable = Py_True;
|
| | if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &enable)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | Selection().enablePickedList(Base::asBoolean(enable));
|
| |
|
| | Py_Return;
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sSetPreselection(PyObject* , PyObject* args, PyObject* kwd)
|
| | {
|
| | PyObject* object;
|
| | const char* subname = nullptr;
|
| | float x = 0, y = 0, z = 0;
|
| | int type = 1;
|
| | static const std::array<const char*, 7> kwlist {"obj", "subname", "x", "y", "z", "tp", nullptr};
|
| | if (Base::Wrapped_ParseTupleAndKeywords(
|
| | args,
|
| | kwd,
|
| | "O!|sfffi",
|
| | kwlist,
|
| | &(App::DocumentObjectPy::Type),
|
| | &object,
|
| | &subname,
|
| | &x,
|
| | &y,
|
| | &z,
|
| | &type
|
| | )) {
|
| | auto docObjPy = static_cast<App::DocumentObjectPy*>(object);
|
| | App::DocumentObject* docObj = docObjPy->getDocumentObjectPtr();
|
| | if (!docObj || !docObj->isAttachedToDocument()) {
|
| | PyErr_SetString(Base::PyExc_FC_GeneralError, "Cannot check invalid object");
|
| | return nullptr;
|
| | }
|
| |
|
| | Selection().setPreselect(
|
| | docObj->getDocument()->getName(),
|
| | docObj->getNameInDocument(),
|
| | subname,
|
| | x,
|
| | y,
|
| | z,
|
| | static_cast<SelectionChanges::MsgSource>(type)
|
| | );
|
| | Py_Return;
|
| | }
|
| |
|
| | PyErr_SetString(PyExc_ValueError, "type must be 'DocumentObject[,subname[,x,y,z]]'");
|
| |
|
| | return nullptr;
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sGetPreselection(PyObject* , PyObject* args)
|
| | {
|
| | if (!PyArg_ParseTuple(args, "")) {
|
| | return nullptr;
|
| | }
|
| |
|
| | const SelectionChanges& sel = Selection().getPreselection();
|
| | SelectionObject obj(sel);
|
| |
|
| | return obj.getPyObject();
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sRemPreselection(PyObject* , PyObject* args)
|
| | {
|
| | if (!PyArg_ParseTuple(args, "")) {
|
| | return nullptr;
|
| | }
|
| |
|
| | Selection().rmvPreselect();
|
| |
|
| | Py_Return;
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sGetCompleteSelection(PyObject* , PyObject* args)
|
| | {
|
| | int resolve = 1;
|
| | if (!PyArg_ParseTuple(args, "|i", &resolve)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | try {
|
| | std::vector<SelectionSingleton::SelObj> sel;
|
| | sel = Selection().getCompleteSelection(toEnum(resolve));
|
| |
|
| | Py::List list;
|
| | for (const auto& it : sel) {
|
| | SelectionObject obj(SelectionChanges(
|
| | SelectionChanges::AddSelection,
|
| | it.DocName,
|
| | it.FeatName,
|
| | it.SubName,
|
| | it.TypeName,
|
| | it.x,
|
| | it.y,
|
| | it.z
|
| | ));
|
| | list.append(Py::asObject(obj.getPyObject()));
|
| | }
|
| | return Py::new_reference_to(list);
|
| | }
|
| | catch (const Base::Exception& e) {
|
| | e.setPyException();
|
| | return nullptr;
|
| | }
|
| | catch (Py::Exception&) {
|
| | return nullptr;
|
| | }
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sGetSelectionEx(PyObject* , PyObject* args)
|
| | {
|
| | char* documentName = nullptr;
|
| | int resolve = 1;
|
| | PyObject* single = Py_False;
|
| | if (!PyArg_ParseTuple(args, "|siO!", &documentName, &resolve, &PyBool_Type, &single)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | try {
|
| | std::vector<SelectionObject> sel;
|
| | sel = Selection().getSelectionEx(
|
| | documentName,
|
| | App::DocumentObject::getClassTypeId(),
|
| | toEnum(resolve),
|
| | Base::asBoolean(single)
|
| | );
|
| |
|
| | Py::List list;
|
| | for (auto& it : sel) {
|
| | list.append(Py::asObject(it.getPyObject()));
|
| | }
|
| | return Py::new_reference_to(list);
|
| | }
|
| | catch (const Base::Exception& e) {
|
| | e.setPyException();
|
| | return nullptr;
|
| | }
|
| | catch (Py::Exception&) {
|
| | return nullptr;
|
| | }
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sGetPickedList(PyObject* , PyObject* args)
|
| | {
|
| | char* documentName = nullptr;
|
| | if (!PyArg_ParseTuple(args, "|s", &documentName)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | std::vector<SelectionObject> sel;
|
| | sel = Selection().getPickedListEx(documentName);
|
| |
|
| | try {
|
| | Py::List list;
|
| | for (auto& it : sel) {
|
| | list.append(Py::asObject(it.getPyObject()));
|
| | }
|
| | return Py::new_reference_to(list);
|
| | }
|
| | catch (Py::Exception&) {
|
| | return nullptr;
|
| | }
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sGetSelectionObject(PyObject* , PyObject* args)
|
| | {
|
| | char *docName, *objName, *subName;
|
| | PyObject* tuple = nullptr;
|
| | if (!PyArg_ParseTuple(args, "sss|O!", &docName, &objName, &subName, &PyTuple_Type, &tuple)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | try {
|
| | SelectionObject selObj;
|
| | selObj.DocName = docName;
|
| | selObj.FeatName = objName;
|
| | std::string sub = subName;
|
| | if (!sub.empty()) {
|
| | selObj.SubNames.push_back(sub);
|
| | if (tuple) {
|
| | Py::Tuple t(tuple);
|
| | double x = (double)Py::Float(t.getItem(0));
|
| | double y = (double)Py::Float(t.getItem(1));
|
| | double z = (double)Py::Float(t.getItem(2));
|
| | selObj.SelPoses.emplace_back(x, y, z);
|
| | }
|
| | }
|
| |
|
| | return selObj.getPyObject();
|
| | }
|
| | catch (const Py::Exception&) {
|
| | return nullptr;
|
| | }
|
| | catch (const Base::Exception& e) {
|
| | e.setPyException();
|
| | return nullptr;
|
| | }
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sSetSelectionStyle(PyObject* , PyObject* args)
|
| | {
|
| | int selStyle = 0;
|
| | if (!PyArg_ParseTuple(args, "i", &selStyle)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | PY_TRY
|
| | {
|
| | Selection().setSelectionStyle(
|
| | selStyle == 0 ? SelectionStyle::NormalSelection : SelectionStyle::GreedySelection
|
| | );
|
| | Py_Return;
|
| | }
|
| | PY_CATCH;
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sAddSelObserver(PyObject* , PyObject* args)
|
| | {
|
| | PyObject* o;
|
| | int resolve = 1;
|
| | if (!PyArg_ParseTuple(args, "O|i", &o, &resolve)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | PY_TRY
|
| | {
|
| | SelectionObserverPython::addObserver(Py::Object(o), toEnum(resolve));
|
| | Py_Return;
|
| | }
|
| | PY_CATCH;
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sRemSelObserver(PyObject* , PyObject* args)
|
| | {
|
| | PyObject* o;
|
| | if (!PyArg_ParseTuple(args, "O", &o)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | PY_TRY
|
| | {
|
| | SelectionObserverPython::removeObserver(Py::Object(o));
|
| | Py_Return;
|
| | }
|
| | PY_CATCH;
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sAddSelectionGate(PyObject* , PyObject* args)
|
| | {
|
| | char* filter;
|
| | int resolve = 1;
|
| | if (PyArg_ParseTuple(args, "s|i", &filter, &resolve)) {
|
| | PY_TRY
|
| | {
|
| | Selection().addSelectionGate(new SelectionFilterGate(filter), toEnum(resolve));
|
| | Py_Return;
|
| | }
|
| | PY_CATCH;
|
| | }
|
| |
|
| | PyErr_Clear();
|
| | PyObject* filterPy;
|
| | if (PyArg_ParseTuple(args, "O!|i", SelectionFilterPy::type_object(), &filterPy, resolve)) {
|
| | PY_TRY
|
| | {
|
| | Selection().addSelectionGate(
|
| | new SelectionFilterGatePython(SelectionFilterPy::cast(filterPy)),
|
| | toEnum(resolve)
|
| | );
|
| | Py_Return;
|
| | }
|
| | PY_CATCH;
|
| | }
|
| |
|
| | PyErr_Clear();
|
| | PyObject* gate;
|
| | if (PyArg_ParseTuple(args, "O|i", &gate, &resolve)) {
|
| | PY_TRY
|
| | {
|
| | Selection().addSelectionGate(
|
| | new SelectionGatePython(Py::Object(gate, false)),
|
| | toEnum(resolve)
|
| | );
|
| | Py_Return;
|
| | }
|
| | PY_CATCH;
|
| | }
|
| |
|
| | PyErr_SetString(PyExc_ValueError, "Argument is neither string nor SelectionFiler nor SelectionGate");
|
| |
|
| | return nullptr;
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sRemoveSelectionGate(PyObject* , PyObject* args)
|
| | {
|
| | if (!PyArg_ParseTuple(args, "")) {
|
| | return nullptr;
|
| | }
|
| |
|
| | PY_TRY
|
| | {
|
| | Selection().rmvSelectionGate();
|
| | Py_Return;
|
| | }
|
| | PY_CATCH;
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sSetVisible(PyObject* , PyObject* args)
|
| | {
|
| | PyObject* visible = Py_None;
|
| | if (!PyArg_ParseTuple(args, "|O", &visible)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | PY_TRY
|
| | {
|
| | VisibleState vis = VisToggle;
|
| | Base::PyTypeCheck(&visible, &PyBool_Type);
|
| | if (visible) {
|
| | vis = PyObject_IsTrue(visible) ? VisShow : VisHide;
|
| | }
|
| |
|
| | Selection().setVisible(vis);
|
| | Py_Return;
|
| | }
|
| | PY_CATCH;
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sPushSelStack(PyObject* , PyObject* args)
|
| | {
|
| | PyObject* clear = Py_True;
|
| | PyObject* overwrite = Py_False;
|
| | if (!PyArg_ParseTuple(args, "|O!O!", &PyBool_Type, &clear, &PyBool_Type, &overwrite)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | Selection().selStackPush(Base::asBoolean(clear), Base::asBoolean(overwrite));
|
| |
|
| | Py_Return;
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sHasSelection(PyObject* , PyObject* args)
|
| | {
|
| | const char* doc = nullptr;
|
| | int resolve = 0;
|
| | if (!PyArg_ParseTuple(args, "|si", &doc, &resolve)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | PY_TRY
|
| | {
|
| | bool ret;
|
| | if (doc || resolve > 0) {
|
| | ret = Selection().hasSelection(doc, toEnum(resolve));
|
| | }
|
| | else {
|
| | ret = Selection().hasSelection();
|
| | }
|
| |
|
| | return Py::new_reference_to(Py::Boolean(ret));
|
| | }
|
| | PY_CATCH;
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sHasSubSelection(PyObject* , PyObject* args)
|
| | {
|
| | const char* doc = nullptr;
|
| | PyObject* subElement = Py_False;
|
| | if (!PyArg_ParseTuple(args, "|sO!", &doc, &PyBool_Type, &subElement)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | PY_TRY
|
| | {
|
| | return Py::new_reference_to(
|
| | Py::Boolean(Selection().hasSubSelection(doc, Base::asBoolean(subElement)))
|
| | );
|
| | }
|
| | PY_CATCH;
|
| | }
|
| |
|
| | PyObject* SelectionSingleton::sGetSelectionFromStack(PyObject* , PyObject* args)
|
| | {
|
| | char* documentName = nullptr;
|
| | int resolve = 1;
|
| | int index = 0;
|
| | if (!PyArg_ParseTuple(args, "|sii", &documentName, &resolve, &index)) {
|
| | return nullptr;
|
| | }
|
| |
|
| | PY_TRY
|
| | {
|
| | Py::List list;
|
| | for (auto& sel : Selection().selStackGet(documentName, toEnum(resolve), index)) {
|
| | list.append(Py::asObject(sel.getPyObject()));
|
| | }
|
| | return Py::new_reference_to(list);
|
| | }
|
| | PY_CATCH;
|
| | }
|
| |
|
| | bool SelectionSingleton::isClarifySelectionActive()
|
| | {
|
| | return clarifySelectionActive;
|
| | }
|
| |
|
| | void SelectionSingleton::setClarifySelectionActive(bool active)
|
| | {
|
| | clarifySelectionActive = active;
|
| | }
|
| |
|