From c9232b141a8cffbe1d0173ef0cc05b4b9f6c8198 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Thu, 18 Jul 2024 09:51:42 -0400 Subject: [PATCH] Toponaming: Transfer in getLinksTo --- src/App/PropertyExpressionEngine.cpp | 44 ++++++++++++ src/App/PropertyExpressionEngine.h | 5 ++ src/App/PropertyLinks.h | 43 ++++++++++++ src/Mod/Part/App/PropertyGeometryList.cpp | 84 ++++++++++++++++++++--- src/Mod/Part/App/PropertyGeometryList.h | 4 +- src/Mod/Part/App/PropertyTopoShape.cpp | 8 ++- src/Mod/Spreadsheet/App/PropertySheet.cpp | 48 +++++++++++++ src/Mod/Spreadsheet/App/PropertySheet.h | 5 ++ 8 files changed, 228 insertions(+), 13 deletions(-) diff --git a/src/App/PropertyExpressionEngine.cpp b/src/App/PropertyExpressionEngine.cpp index 0eac59bf2a..95899113de 100644 --- a/src/App/PropertyExpressionEngine.cpp +++ b/src/App/PropertyExpressionEngine.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1079,3 +1080,46 @@ void PropertyExpressionEngine::onRelabeledDocument(const App::Document &doc) e.second.expression->visit(v); } } + +void PropertyExpressionEngine::getLinksTo(std::vector &identifiers, + App::DocumentObject *obj, + const char *subname, + bool all) const +{ + Expression::DepOption option = all ? Expression::DepOption::DepAll + : Expression::DepOption::DepNormal; + + App::SubObjectT objT(obj, subname); + auto sobj = objT.getSubObject(); + auto subElement = objT.getOldElementName(); + + for(auto &v : expressions) { + const auto &deps = v.second.expression->getDeps(option); + auto it = deps.find(obj); + if(it==deps.end()) + continue; + for(auto &dep : it->second) { + if (!subname) { + identifiers.push_back(v.first); + break; + } + bool found = false; + for (const auto &path : dep.second) { + if (path.getSubObjectName() == subname) { + identifiers.push_back(v.first); + found = true; + break; + } + App::SubObjectT sobjT(obj, path.getSubObjectName().c_str()); + if (sobjT.getSubObject() == sobj + && sobjT.getOldElementName() == subElement) { + identifiers.push_back(v.first); + found = true; + break; + } + } + if (found) + break; + } + } +} diff --git a/src/App/PropertyExpressionEngine.h b/src/App/PropertyExpressionEngine.h index 05f9febd3e..b571cc764b 100644 --- a/src/App/PropertyExpressionEngine.h +++ b/src/App/PropertyExpressionEngine.h @@ -160,6 +160,11 @@ public: void afterRestore() override; void onContainerRestored() override; + virtual void getLinksTo(std::vector &identifiers, + App::DocumentObject *obj, + const char *subname=nullptr, + bool all=false) const override; + /* Python interface */ PyObject *getPyObject() override; void setPyObject(PyObject *) override; diff --git a/src/App/PropertyLinks.h b/src/App/PropertyLinks.h index 29b7a7e547..99b6955be9 100644 --- a/src/App/PropertyLinks.h +++ b/src/App/PropertyLinks.h @@ -184,6 +184,19 @@ public: virtual void getLinks(std::vector &objs, bool all=false, std::vector *subs=nullptr, bool newStyle=true) const = 0; + /** Obtain identifiers from this link property that link to a give object + * @param identifiers: holds the returned identifier to reference the given object + * @param obj: the referenced object + * @param subname: optional subname reference + * @param all: if true, then return all the references regardless of + * this LinkScope. If false, then return only if the LinkScope + * is not hidden. + */ + virtual void getLinksTo(std::vector &identifiers, + App::DocumentObject *obj, + const char *subname=nullptr, + bool all=false) const = 0; + /** Called to reset this link property * * @param obj: reset link property if it is linked to this object @@ -631,6 +644,11 @@ public: void getLinks(std::vector &objs, bool all=false, std::vector *subs=nullptr, bool newStyle=true) const override; + void getLinksTo(std::vector &identifiers, + App::DocumentObject *obj, + const char *subname=nullptr, + bool all=false) const override; + void breakLink(App::DocumentObject *obj, bool clear) override; bool adjustLink(const std::set &inList) override; @@ -721,6 +739,11 @@ public: void getLinks(std::vector &objs, bool all=false, std::vector *subs=nullptr, bool newStyle=true) const override; + void getLinksTo(std::vector &identifiers, + App::DocumentObject *obj, + const char *subname=nullptr, + bool all=false) const override; + void breakLink(App::DocumentObject *obj, bool clear) override; bool adjustLink(const std::set &inList) override; @@ -862,6 +885,11 @@ public: void getLinks(std::vector &objs, bool all=false, std::vector *subs=nullptr, bool newStyle=true) const override; + void getLinksTo(std::vector &identifiers, + App::DocumentObject *obj, + const char *subname=nullptr, + bool all=false) const override; + void breakLink(App::DocumentObject *obj, bool clear) override; bool adjustLink(const std::set &inList) override; @@ -1009,6 +1037,11 @@ public: void getLinks(std::vector &objs, bool all=false, std::vector *subs=nullptr, bool newStyle=true) const override; + void getLinksTo(std::vector &identifiers, + App::DocumentObject *obj, + const char *subname=nullptr, + bool all=false) const override; + void breakLink(App::DocumentObject *obj, bool clear) override; bool adjustLink(const std::set &inList) override; @@ -1132,6 +1165,11 @@ public: void getLinks(std::vector &objs, bool all=false, std::vector *subs=nullptr, bool newStyle=true) const override; + void getLinksTo(std::vector &identifiers, + App::DocumentObject *obj, + const char *subname=nullptr, + bool all=false) const override; + bool adjustLink(const std::set &inList) override; const std::vector& getSubValues() const { @@ -1302,6 +1340,11 @@ public: void getLinks(std::vector &objs, bool all=false, std::vector *subs=nullptr, bool newStyle=true) const override; + void getLinksTo(std::vector &identifiers, + App::DocumentObject *obj, + const char *subname=nullptr, + bool all=false) const override; + void breakLink(App::DocumentObject *obj, bool clear) override; bool adjustLink(const std::set &inList) override; diff --git a/src/Mod/Part/App/PropertyGeometryList.cpp b/src/Mod/Part/App/PropertyGeometryList.cpp index 23f9660721..27f44c5367 100644 --- a/src/Mod/Part/App/PropertyGeometryList.cpp +++ b/src/Mod/Part/App/PropertyGeometryList.cpp @@ -27,6 +27,7 @@ #include #include "PropertyGeometryList.h" +#include "GeometryMigrationExtension.h" #include "GeometryPy.h" #include "Part2DObject.h" @@ -84,26 +85,55 @@ void PropertyGeometryList::setValue(const Geometry* lValue) void PropertyGeometryList::setValues(const std::vector& lValue) { auto copy = lValue; - for(auto &geo : copy) // copy of the individual geometry pointers - geo = geo->clone(); - - setValues(std::move(copy)); +// for(auto &geo : copy) // copy of the individual geometry pointers +// geo = geo->clone(); +// +// setValues(std::move(copy)); + aboutToSetValue(); + std::sort(_lValueList.begin(), _lValueList.end()); + for (auto &v : copy) { + auto range = std::equal_range(_lValueList.begin(), _lValueList.end(), v); + // clone if the new entry does not exist in the original value list, or + // else, simply reuse it (i.e. erase it so that it won't get deleted below). + if (range.first == range.second) + v = v->clone(); + else + _lValueList.erase(range.first, range.second); + } + for (auto v : _lValueList) + delete v; + _lValueList = std::move(copy); + hasSetValue(); } void PropertyGeometryList::setValues(std::vector &&lValue) { +// aboutToSetValue(); +// std::set valueSet(_lValueList.begin(),_lValueList.end()); +// for(auto v : lValue) +// valueSet.erase(v); +// _lValueList = std::move(lValue); +// for(auto v : valueSet) +// delete v; +// hasSetValue(); + // Unlike above, the moved version of setValues() indicates the caller want + // us to manager the memory of the passed in values. So no need clone. aboutToSetValue(); - std::set valueSet(_lValueList.begin(),_lValueList.end()); - for(auto v : lValue) - valueSet.erase(v); - _lValueList = std::move(lValue); - for(auto v : valueSet) + std::sort(_lValueList.begin(), _lValueList.end()); + for (auto v : lValue) { + auto range = std::equal_range(_lValueList.begin(), _lValueList.end(), v); + _lValueList.erase(range.first, range.second); + } + for (auto v : _lValueList) delete v; + _lValueList = std::move(lValue); hasSetValue(); } void PropertyGeometryList::set1Value(int idx, std::unique_ptr &&lValue) { + if (!lValue) + return; if(idx>=(int)_lValueList.size()) throw Base::IndexError("Index out of bound"); aboutToSetValue(); @@ -171,6 +201,12 @@ void PropertyGeometryList::trySaveGeometry(Geometry * geom, Base::Writer &writer // Not all geometry classes implement Save() and throw an exception instead try { geom->Save(writer); + for( auto &e : geom->getExtensions() ) { + auto ext = e.lock(); + auto gpe = freecad_dynamic_cast(ext.get()); + if (gpe) + gpe->postSave(writer); + } } catch (const Base::NotImplementedError& e) { Base::Console().Warning(std::string("PropertyGeometryList"), "Not yet implemented: %s\n", e.what()); @@ -181,6 +217,17 @@ void PropertyGeometryList::tryRestoreGeometry(Geometry * geom, Base::XMLReader & { // Not all geometry classes implement Restore() and throw an exception instead try { + if (!reader.getAttributeAsInteger("migrated") && reader.hasAttribute("id")) { + auto ext = std::make_unique(); + ext->setId(reader.getAttributeAsInteger("id")); + if(reader.hasAttribute("ref")) { + const char *ref = reader.getAttribute("ref"); + int index = reader.getAttributeAsInteger("refIndex"); + unsigned long flags = (unsigned long)reader.getAttributeAsUnsigned("flags"); + ext->setReference(ref, index, flags); + } + geom->setExtension(std::move(ext)); + } geom->Restore(reader); } catch (const Base::NotImplementedError& e) { @@ -193,8 +240,16 @@ void PropertyGeometryList::Save(Writer &writer) const writer.Stream() << writer.ind() << "" << endl; writer.incInd(); for (int i = 0; i < getSize(); i++) { - writer.Stream() << writer.ind() << "getTypeId().getName() << "\">" << endl;; + writer.Stream() << writer.ind() << "getTypeId().getName() << "\""; + for( auto &e : _lValueList[i]->getExtensions() ) { + auto ext = e.lock(); + auto gpe = freecad_dynamic_cast(ext.get()); + if (gpe) + gpe->preSave(writer); + } + writer.Stream() << " migrated=\"1\">\n"; + writer.incInd(); trySaveGeometry(_lValueList[i], writer); writer.decInd(); @@ -263,3 +318,10 @@ unsigned int PropertyGeometryList::getMemSize() const size += _lValueList[i]->getMemSize(); return size; } + +void PropertyGeometryList::moveValues(PropertyGeometryList &&other) +{ + setValues(std::move(other._lValueList)); +} + + diff --git a/src/Mod/Part/App/PropertyGeometryList.h b/src/Mod/Part/App/PropertyGeometryList.h index a8aa343512..c9b6498232 100644 --- a/src/Mod/Part/App/PropertyGeometryList.h +++ b/src/Mod/Part/App/PropertyGeometryList.h @@ -64,8 +64,10 @@ public: void setValues(const std::vector&); void setValues(std::vector&&); + void moveValues(PropertyGeometryList &&other); + /// index operator - const Geometry *operator[] (const int idx) const { + Geometry *operator[] (const int idx) const { return _lValueList[idx]; } diff --git a/src/Mod/Part/App/PropertyTopoShape.cpp b/src/Mod/Part/App/PropertyTopoShape.cpp index 4b5fb2f413..82b4050f01 100644 --- a/src/Mod/Part/App/PropertyTopoShape.cpp +++ b/src/Mod/Part/App/PropertyTopoShape.cpp @@ -303,8 +303,14 @@ void PropertyPartShape::Save (Base::Writer &writer) const writer.Stream() << " file=\"" << writer.addFile(getFileName(binary?".bin":".brp").c_str(), this) << "\"/>\n"; + } else if(binary) { + writer.Stream() << " binary=\"1\">\n"; + _Shape.exportBinary(writer.beginCharStream(Base::CharStreamFormat::Base64Encoded)); + writer.endCharStream() << writer.ind() << "\n"; } else { - writer.Stream() << "/>\n"; + writer.Stream() << " brep=\"1\">\n"; + _Shape.exportBrep(writer.beginCharStream(Base::CharStreamFormat::Raw)<<'\n'); + writer.endCharStream() << '\n' << writer.ind() << "\n"; } if(_SaveHasher) { diff --git a/src/Mod/Spreadsheet/App/PropertySheet.cpp b/src/Mod/Spreadsheet/App/PropertySheet.cpp index 742f380d6d..02b4d5cdd3 100644 --- a/src/Mod/Spreadsheet/App/PropertySheet.cpp +++ b/src/Mod/Spreadsheet/App/PropertySheet.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -2267,3 +2268,50 @@ bool PropertySheet::hasSpan() const { return !mergedCells.empty(); } + +void PropertySheet::getLinksTo(std::vector& identifiers, + App::DocumentObject* obj, + const char* subname, + bool all) const +{ + Expression::DepOption option = + all ? Expression::DepOption::DepAll : Expression::DepOption::DepNormal; + + App::SubObjectT objT(obj, subname); + auto sobj = objT.getSubObject(); + auto subElement = objT.getOldElementName(); + + auto owner = Base::freecad_dynamic_cast(getContainer()); + for (const auto& v : data) { + if (auto expr = v.second->getExpression()) { + const auto& deps = expr->getDeps(option); + auto it = deps.find(obj); + if (it == deps.end()) { + continue; + } + for (auto& dep : it->second) { + if (!subname) { + identifiers.emplace_back(owner, v.first.toString().c_str()); + break; + } + bool found = false; + for (const auto& path : dep.second) { + if (path.getSubObjectName() == subname) { + identifiers.emplace_back(owner, v.first.toString().c_str()); + found = true; + break; + } + App::SubObjectT sobjT(obj, path.getSubObjectName().c_str()); + if (sobjT.getSubObject() == sobj && sobjT.getOldElementName() == subElement) { + identifiers.emplace_back(owner, v.first.toString().c_str()); + found = true; + break; + } + } + if (found) { + break; + } + } + } + } +} diff --git a/src/Mod/Spreadsheet/App/PropertySheet.h b/src/Mod/Spreadsheet/App/PropertySheet.h index 500e78d48c..9ff409dc41 100644 --- a/src/Mod/Spreadsheet/App/PropertySheet.h +++ b/src/Mod/Spreadsheet/App/PropertySheet.h @@ -78,6 +78,11 @@ public: void Restore(Base::XMLReader& reader) override; + virtual void getLinksTo(std::vector& identifiers, + App::DocumentObject* obj, + const char* subname = nullptr, + bool all = false) const override; + void copyCells(Base::Writer& writer, const std::vector& ranges) const; void pasteCells(Base::XMLReader& reader, App::Range dstRange);