App: Apply clang format (part 1)
This commit is contained in:
@@ -45,7 +45,7 @@ PROPERTY_SOURCE(App::AnnotationLabel, App::DocumentObject)
|
||||
|
||||
AnnotationLabel::AnnotationLabel()
|
||||
{
|
||||
ADD_PROPERTY_TYPE(LabelText, (""), "Label",Prop_Output, "Text label of the annotation");
|
||||
ADD_PROPERTY_TYPE(LabelText, (""), "Label", Prop_Output, "Text label of the annotation");
|
||||
ADD_PROPERTY_TYPE(BasePosition, (Base::Vector3d()), "Label", Prop_Output, "Base position");
|
||||
ADD_PROPERTY_TYPE(TextPosition, (Base::Vector3d()), "Label", Prop_Output, "Text position");
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
namespace App
|
||||
{
|
||||
|
||||
class AppExport Annotation : public DocumentObject
|
||||
class AppExport Annotation: public DocumentObject
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(App::Annotation);
|
||||
|
||||
@@ -45,12 +45,13 @@ public:
|
||||
App::PropertyVector Position;
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
const char* getViewProviderName() const override {
|
||||
const char* getViewProviderName() const override
|
||||
{
|
||||
return "Gui::ViewProviderAnnotation";
|
||||
}
|
||||
};
|
||||
|
||||
class AppExport AnnotationLabel : public DocumentObject
|
||||
class AppExport AnnotationLabel: public DocumentObject
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(App::AnnotationLabel);
|
||||
|
||||
@@ -64,12 +65,13 @@ public:
|
||||
App::PropertyVector TextPosition;
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
const char* getViewProviderName() const override {
|
||||
const char* getViewProviderName() const override
|
||||
{
|
||||
return "Gui::ViewProviderAnnotationLabel";
|
||||
}
|
||||
};
|
||||
|
||||
} //namespace App
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // APP_ANNOTATION_H
|
||||
#endif // APP_ANNOTATION_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -37,12 +37,11 @@ using namespace App;
|
||||
static int _TransactionLock;
|
||||
static int _TransactionClosed;
|
||||
|
||||
AutoTransaction::AutoTransaction(const char *name, bool tmpName) {
|
||||
auto &app = GetApplication();
|
||||
if(name && app._activeTransactionGuard>=0) {
|
||||
if(!app.getActiveTransaction()
|
||||
|| (!tmpName && app._activeTransactionTmpName))
|
||||
{
|
||||
AutoTransaction::AutoTransaction(const char* name, bool tmpName)
|
||||
{
|
||||
auto& app = GetApplication();
|
||||
if (name && app._activeTransactionGuard >= 0) {
|
||||
if (!app.getActiveTransaction() || (!tmpName && app._activeTransactionTmpName)) {
|
||||
FC_LOG("auto transaction '" << name << "', " << tmpName);
|
||||
tid = app.setActiveTransaction(name);
|
||||
app._activeTransactionTmpName = tmpName;
|
||||
@@ -52,166 +51,206 @@ AutoTransaction::AutoTransaction(const char *name, bool tmpName) {
|
||||
// and any stack below. This is to support user setting active transaction
|
||||
// before having any existing AutoTransaction on stack, or 'persist'
|
||||
// transaction that can out live AutoTransaction.
|
||||
if(app._activeTransactionGuard<0)
|
||||
if (app._activeTransactionGuard < 0) {
|
||||
--app._activeTransactionGuard;
|
||||
else if(tid || app._activeTransactionGuard>0)
|
||||
}
|
||||
else if (tid || app._activeTransactionGuard > 0) {
|
||||
++app._activeTransactionGuard;
|
||||
else if(app.getActiveTransaction()) {
|
||||
}
|
||||
else if (app.getActiveTransaction()) {
|
||||
FC_LOG("auto transaction disabled because of '" << app._activeTransactionName << "'");
|
||||
--app._activeTransactionGuard;
|
||||
} else
|
||||
}
|
||||
else {
|
||||
++app._activeTransactionGuard;
|
||||
}
|
||||
FC_TRACE("construct auto Transaction " << app._activeTransactionGuard);
|
||||
}
|
||||
|
||||
AutoTransaction::~AutoTransaction() {
|
||||
auto &app = GetApplication();
|
||||
AutoTransaction::~AutoTransaction()
|
||||
{
|
||||
auto& app = GetApplication();
|
||||
FC_TRACE("before destruct auto Transaction " << app._activeTransactionGuard);
|
||||
if(app._activeTransactionGuard<0)
|
||||
if (app._activeTransactionGuard < 0) {
|
||||
++app._activeTransactionGuard;
|
||||
else if(!app._activeTransactionGuard) {
|
||||
}
|
||||
else if (!app._activeTransactionGuard) {
|
||||
#ifdef FC_DEBUG
|
||||
FC_ERR("Transaction guard error");
|
||||
#endif
|
||||
} else if(--app._activeTransactionGuard == 0) {
|
||||
}
|
||||
else if (--app._activeTransactionGuard == 0) {
|
||||
try {
|
||||
// We don't call close() here, because close() only closes
|
||||
// transaction that we opened during construction time. However,
|
||||
// when _activeTransactionGuard reaches zero here, we are supposed
|
||||
// to close any transaction opened.
|
||||
app.closeActiveTransaction();
|
||||
} catch(Base::Exception &e) {
|
||||
}
|
||||
catch (Base::Exception& e) {
|
||||
e.ReportException();
|
||||
} catch(...)
|
||||
{}
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
}
|
||||
FC_TRACE("destruct auto Transaction " << app._activeTransactionGuard);
|
||||
}
|
||||
|
||||
void AutoTransaction::close(bool abort) {
|
||||
if(tid || abort) {
|
||||
GetApplication().closeActiveTransaction(abort,abort?0:tid);
|
||||
void AutoTransaction::close(bool abort)
|
||||
{
|
||||
if (tid || abort) {
|
||||
GetApplication().closeActiveTransaction(abort, abort ? 0 : tid);
|
||||
tid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void AutoTransaction::setEnable(bool enable) {
|
||||
auto &app = GetApplication();
|
||||
if(!app._activeTransactionGuard)
|
||||
void AutoTransaction::setEnable(bool enable)
|
||||
{
|
||||
auto& app = GetApplication();
|
||||
if (!app._activeTransactionGuard) {
|
||||
return;
|
||||
if((enable && app._activeTransactionGuard>0)
|
||||
|| (!enable && app._activeTransactionGuard<0))
|
||||
}
|
||||
if ((enable && app._activeTransactionGuard > 0)
|
||||
|| (!enable && app._activeTransactionGuard < 0)) {
|
||||
return;
|
||||
}
|
||||
app._activeTransactionGuard = -app._activeTransactionGuard;
|
||||
FC_TRACE("toggle auto Transaction " << app._activeTransactionGuard);
|
||||
if(!enable && app._activeTransactionTmpName) {
|
||||
if (!enable && app._activeTransactionTmpName) {
|
||||
bool close = true;
|
||||
for(auto &v : app.DocMap) {
|
||||
if(v.second->hasPendingTransaction()) {
|
||||
for (auto& v : app.DocMap) {
|
||||
if (v.second->hasPendingTransaction()) {
|
||||
close = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(close)
|
||||
if (close) {
|
||||
app.closeActiveTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Application::setActiveTransaction(const char *name, bool persist) {
|
||||
if(!name || !name[0])
|
||||
int Application::setActiveTransaction(const char* name, bool persist)
|
||||
{
|
||||
if (!name || !name[0]) {
|
||||
name = "Command";
|
||||
}
|
||||
|
||||
if(_activeTransactionGuard>0 && getActiveTransaction()) {
|
||||
if(_activeTransactionTmpName) {
|
||||
if (_activeTransactionGuard > 0 && getActiveTransaction()) {
|
||||
if (_activeTransactionTmpName) {
|
||||
FC_LOG("transaction rename to '" << name << "'");
|
||||
for(auto &v : DocMap)
|
||||
v.second->renameTransaction(name,_activeTransactionID);
|
||||
} else {
|
||||
if(persist)
|
||||
for (auto& v : DocMap) {
|
||||
v.second->renameTransaction(name, _activeTransactionID);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (persist) {
|
||||
AutoTransaction::setEnable(false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} else if (_TransactionLock) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG))
|
||||
}
|
||||
else if (_TransactionLock) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("Transaction locked, ignore new transaction '" << name << "'");
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
FC_LOG("set active transaction '" << name << "'");
|
||||
_activeTransactionID = 0;
|
||||
for(auto &v : DocMap)
|
||||
for (auto& v : DocMap) {
|
||||
v.second->_commitTransaction();
|
||||
}
|
||||
_activeTransactionID = Transaction::getNewID();
|
||||
}
|
||||
_activeTransactionTmpName = false;
|
||||
_activeTransactionName = name;
|
||||
if(persist)
|
||||
if (persist) {
|
||||
AutoTransaction::setEnable(false);
|
||||
}
|
||||
return _activeTransactionID;
|
||||
}
|
||||
|
||||
const char *Application::getActiveTransaction(int *id) const {
|
||||
const char* Application::getActiveTransaction(int* id) const
|
||||
{
|
||||
int tid = 0;
|
||||
if(Transaction::getLastID() == _activeTransactionID)
|
||||
if (Transaction::getLastID() == _activeTransactionID) {
|
||||
tid = _activeTransactionID;
|
||||
if (id)
|
||||
}
|
||||
if (id) {
|
||||
*id = tid;
|
||||
}
|
||||
return tid ? _activeTransactionName.c_str() : nullptr;
|
||||
}
|
||||
|
||||
void Application::closeActiveTransaction(bool abort, int id) {
|
||||
if(!id) id = _activeTransactionID;
|
||||
if(!id)
|
||||
void Application::closeActiveTransaction(bool abort, int id)
|
||||
{
|
||||
if (!id) {
|
||||
id = _activeTransactionID;
|
||||
}
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(_activeTransactionGuard>0 && !abort) {
|
||||
if (_activeTransactionGuard > 0 && !abort) {
|
||||
FC_LOG("ignore close transaction");
|
||||
return;
|
||||
}
|
||||
|
||||
if(_TransactionLock) {
|
||||
if(_TransactionClosed >= 0)
|
||||
_TransactionLock = abort?-1:1;
|
||||
FC_LOG("pending " << (abort?"abort":"close") << " transaction");
|
||||
if (_TransactionLock) {
|
||||
if (_TransactionClosed >= 0) {
|
||||
_TransactionLock = abort ? -1 : 1;
|
||||
}
|
||||
FC_LOG("pending " << (abort ? "abort" : "close") << " transaction");
|
||||
return;
|
||||
}
|
||||
|
||||
FC_LOG("close transaction '" << _activeTransactionName << "' " << abort);
|
||||
_activeTransactionID = 0;
|
||||
|
||||
TransactionSignaller signaller(abort,false);
|
||||
for(auto &v : DocMap) {
|
||||
if(v.second->getTransactionID(true) != id)
|
||||
TransactionSignaller signaller(abort, false);
|
||||
for (auto& v : DocMap) {
|
||||
if (v.second->getTransactionID(true) != id) {
|
||||
continue;
|
||||
if(abort)
|
||||
}
|
||||
if (abort) {
|
||||
v.second->_abortTransaction();
|
||||
else
|
||||
}
|
||||
else {
|
||||
v.second->_commitTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TransactionLocker::TransactionLocker(bool lock)
|
||||
:active(lock)
|
||||
: active(lock)
|
||||
{
|
||||
if(lock)
|
||||
if (lock) {
|
||||
++_TransactionLock;
|
||||
}
|
||||
}
|
||||
|
||||
TransactionLocker::~TransactionLocker()
|
||||
{
|
||||
if(active) {
|
||||
if (active) {
|
||||
try {
|
||||
activate(false);
|
||||
return;
|
||||
} catch (Base::Exception &e) {
|
||||
}
|
||||
catch (Base::Exception& e) {
|
||||
e.ReportException();
|
||||
} catch (Py::Exception &) {
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e;
|
||||
e.ReportException();
|
||||
} catch (std::exception &e) {
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
FC_ERR(e.what());
|
||||
} catch (...) {
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
FC_ERR("Exception when unlocking transaction");
|
||||
}
|
||||
@@ -219,26 +258,28 @@ TransactionLocker::~TransactionLocker()
|
||||
|
||||
void TransactionLocker::activate(bool enable)
|
||||
{
|
||||
if(active == enable)
|
||||
if (active == enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
active = enable;
|
||||
if(active) {
|
||||
if (active) {
|
||||
++_TransactionLock;
|
||||
return;
|
||||
}
|
||||
|
||||
if(--_TransactionLock != 0)
|
||||
if (--_TransactionLock != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(_TransactionClosed) {
|
||||
bool abort = (_TransactionClosed<0);
|
||||
if (_TransactionClosed) {
|
||||
bool abort = (_TransactionClosed < 0);
|
||||
_TransactionClosed = 0;
|
||||
GetApplication().closeActiveTransaction(abort);
|
||||
}
|
||||
}
|
||||
|
||||
bool TransactionLocker::isLocked() {
|
||||
bool TransactionLocker::isLocked()
|
||||
{
|
||||
return _TransactionLock > 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,15 +26,17 @@
|
||||
#include <cstddef>
|
||||
#include <FCGlobal.h>
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
|
||||
class Application;
|
||||
|
||||
/// Helper class to manager transaction (i.e. undo/redo)
|
||||
class AppExport AutoTransaction {
|
||||
class AppExport AutoTransaction
|
||||
{
|
||||
public:
|
||||
/// Private new operator to prevent heap allocation
|
||||
void* operator new (std::size_t) = delete;
|
||||
void* operator new(std::size_t) = delete;
|
||||
|
||||
public:
|
||||
/** Constructor
|
||||
@@ -51,7 +53,7 @@ public:
|
||||
* current active transaction until it reaches zero. It does not have any
|
||||
* effect on aborting transaction, though.
|
||||
*/
|
||||
AutoTransaction(const char *name=nullptr, bool tmpName=false);
|
||||
AutoTransaction(const char* name = nullptr, bool tmpName = false);
|
||||
|
||||
/** Destructor
|
||||
*
|
||||
@@ -67,7 +69,7 @@ public:
|
||||
* transaction, if the current transaction ID matches the one created inside
|
||||
* the constructor. For aborting, it will abort any current transaction
|
||||
*/
|
||||
void close(bool abort=false);
|
||||
void close(bool abort = false);
|
||||
|
||||
/** Enable/Disable any AutoTransaction instance in the current stack
|
||||
*
|
||||
@@ -90,13 +92,13 @@ private:
|
||||
* The helper class is used to protect some critical transaction from being
|
||||
* closed prematurely, e.g. when deleting some object.
|
||||
*/
|
||||
class AppExport TransactionLocker {
|
||||
class AppExport TransactionLocker
|
||||
{
|
||||
public:
|
||||
|
||||
/** Constructor
|
||||
* @param lock: whether to activate the lock
|
||||
*/
|
||||
TransactionLocker(bool lock=true);
|
||||
TransactionLocker(bool lock = true);
|
||||
|
||||
/** Destructor
|
||||
* Unlock the transaction is this locker is active
|
||||
@@ -114,7 +116,10 @@ public:
|
||||
void activate(bool enable);
|
||||
|
||||
/// Check if the locker is active
|
||||
bool isActive() const {return active;}
|
||||
bool isActive() const
|
||||
{
|
||||
return active;
|
||||
}
|
||||
|
||||
/// Check if transaction is being locked
|
||||
static bool isLocked();
|
||||
@@ -123,12 +128,12 @@ public:
|
||||
|
||||
public:
|
||||
/// Private new operator to prevent heap allocation
|
||||
void* operator new (std::size_t) = delete;
|
||||
void* operator new(std::size_t) = delete;
|
||||
|
||||
private:
|
||||
bool active;
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_AUTOTRANSACTION_H
|
||||
#endif // APP_AUTOTRANSACTION_H
|
||||
|
||||
@@ -63,10 +63,12 @@ Branding::Branding()
|
||||
bool Branding::readFile(const QString& fn)
|
||||
{
|
||||
QFile file(fn);
|
||||
if (!file.open(QFile::ReadOnly))
|
||||
if (!file.open(QFile::ReadOnly)) {
|
||||
return false;
|
||||
if (!evaluateXML(&file, domDocument))
|
||||
}
|
||||
if (!evaluateXML(&file, domDocument)) {
|
||||
return false;
|
||||
}
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
@@ -81,22 +83,22 @@ Branding::XmlConfig Branding::getUserDefines() const
|
||||
while (!child.isNull()) {
|
||||
std::string name = child.localName().toLatin1().constData();
|
||||
std::string value = child.text().toUtf8().constData();
|
||||
if (std::find(filter.begin(), filter.end(), name) != filter.end())
|
||||
if (std::find(filter.begin(), filter.end(), name) != filter.end()) {
|
||||
cfg[name] = value;
|
||||
}
|
||||
child = child.nextSiblingElement();
|
||||
}
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
|
||||
bool Branding::evaluateXML(QIODevice *device, QDomDocument& xmlDocument)
|
||||
bool Branding::evaluateXML(QIODevice* device, QDomDocument& xmlDocument)
|
||||
{
|
||||
QString errorStr;
|
||||
int errorLine;
|
||||
int errorColumn;
|
||||
|
||||
if (!xmlDocument.setContent(device, true, &errorStr, &errorLine,
|
||||
&errorColumn)) {
|
||||
if (!xmlDocument.setContent(device, true, &errorStr, &errorLine, &errorColumn)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -106,8 +108,9 @@ bool Branding::evaluateXML(QIODevice *device, QDomDocument& xmlDocument)
|
||||
}
|
||||
else if (root.hasAttribute(QLatin1String("version"))) {
|
||||
QString attr = root.attribute(QLatin1String("version"));
|
||||
if (attr != QLatin1String("1.0"))
|
||||
if (attr != QLatin1String("1.0")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
|
||||
class QIODevice;
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
|
||||
class Branding
|
||||
{
|
||||
@@ -46,10 +47,10 @@ public:
|
||||
|
||||
private:
|
||||
QVector<std::string> filter;
|
||||
bool evaluateXML(QIODevice *device, QDomDocument& xmlDocument);
|
||||
bool evaluateXML(QIODevice* device, QDomDocument& xmlDocument);
|
||||
QDomDocument domDocument;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_BRANDING_H
|
||||
#endif // APP_BRANDING_H
|
||||
|
||||
@@ -31,7 +31,7 @@ using namespace App;
|
||||
|
||||
namespace
|
||||
{
|
||||
static std::list<std::function<void()>> cleanup_funcs; // NOLINT
|
||||
static std::list<std::function<void()>> cleanup_funcs; // NOLINT
|
||||
}
|
||||
|
||||
void CleanupProcess::registerCleanup(const std::function<void()>& func)
|
||||
|
||||
@@ -52,6 +52,6 @@ public:
|
||||
static void callCleanup();
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_CLEANUPPROCESS_H
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
# include <memory>
|
||||
#include <memory>
|
||||
#endif
|
||||
|
||||
#include "ComplexGeoData.h"
|
||||
@@ -50,10 +50,11 @@ std::string ComplexGeoDataPy::representation() const
|
||||
return {"<ComplexGeoData object>"};
|
||||
}
|
||||
|
||||
PyObject* ComplexGeoDataPy::getElementTypes(PyObject *args)
|
||||
PyObject* ComplexGeoDataPy::getElementTypes(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<const char*> types = getComplexGeoDataPtr()->getElementTypes();
|
||||
Py::List list;
|
||||
@@ -63,11 +64,12 @@ PyObject* ComplexGeoDataPy::getElementTypes(PyObject *args)
|
||||
return Py::new_reference_to(list);
|
||||
}
|
||||
|
||||
PyObject* ComplexGeoDataPy::countSubElements(PyObject *args)
|
||||
PyObject* ComplexGeoDataPy::countSubElements(PyObject* args)
|
||||
{
|
||||
char *type;
|
||||
if (!PyArg_ParseTuple(args, "s", &type))
|
||||
char* type;
|
||||
if (!PyArg_ParseTuple(args, "s", &type)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
unsigned long count = getComplexGeoDataPtr()->countSubElements(type);
|
||||
@@ -79,12 +81,13 @@ PyObject* ComplexGeoDataPy::countSubElements(PyObject *args)
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* ComplexGeoDataPy::getFacesFromSubElement(PyObject *args)
|
||||
PyObject* ComplexGeoDataPy::getFacesFromSubElement(PyObject* args)
|
||||
{
|
||||
char *type;
|
||||
char* type;
|
||||
unsigned long index;
|
||||
if (!PyArg_ParseTuple(args, "sk", &type, &index))
|
||||
if (!PyArg_ParseTuple(args, "sk", &type, &index)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<Base::Vector3d> points;
|
||||
std::vector<Base::Vector3d> normals;
|
||||
@@ -100,27 +103,29 @@ PyObject* ComplexGeoDataPy::getFacesFromSubElement(PyObject *args)
|
||||
|
||||
Py::Tuple tuple(2);
|
||||
Py::List vertex;
|
||||
for (const auto & it : points)
|
||||
for (const auto& it : points) {
|
||||
vertex.append(Py::asObject(new Base::VectorPy(it)));
|
||||
}
|
||||
tuple.setItem(0, vertex);
|
||||
Py::List facet;
|
||||
for (const auto & it : facets) {
|
||||
for (const auto& it : facets) {
|
||||
Py::Tuple f(3);
|
||||
f.setItem(0,Py::Int(int(it.I1)));
|
||||
f.setItem(1,Py::Int(int(it.I2)));
|
||||
f.setItem(2,Py::Int(int(it.I3)));
|
||||
f.setItem(0, Py::Int(int(it.I1)));
|
||||
f.setItem(1, Py::Int(int(it.I2)));
|
||||
f.setItem(2, Py::Int(int(it.I3)));
|
||||
facet.append(f);
|
||||
}
|
||||
tuple.setItem(1, facet);
|
||||
return Py::new_reference_to(tuple);
|
||||
}
|
||||
|
||||
PyObject* ComplexGeoDataPy::getLinesFromSubElement(PyObject *args)
|
||||
PyObject* ComplexGeoDataPy::getLinesFromSubElement(PyObject* args)
|
||||
{
|
||||
char *type;
|
||||
char* type;
|
||||
int index;
|
||||
if (!PyArg_ParseTuple(args, "si", &type, &index))
|
||||
if (!PyArg_ParseTuple(args, "si", &type, &index)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<Base::Vector3d> points;
|
||||
std::vector<Data::ComplexGeoData::Line> lines;
|
||||
@@ -135,25 +140,27 @@ PyObject* ComplexGeoDataPy::getLinesFromSubElement(PyObject *args)
|
||||
|
||||
Py::Tuple tuple(2);
|
||||
Py::List vertex;
|
||||
for (const auto & it : points)
|
||||
for (const auto& it : points) {
|
||||
vertex.append(Py::asObject(new Base::VectorPy(it)));
|
||||
}
|
||||
tuple.setItem(0, vertex);
|
||||
Py::List line;
|
||||
for (const auto & it : lines) {
|
||||
for (const auto& it : lines) {
|
||||
Py::Tuple l(2);
|
||||
l.setItem(0,Py::Int((int)it.I1));
|
||||
l.setItem(1,Py::Int((int)it.I2));
|
||||
l.setItem(0, Py::Int((int)it.I1));
|
||||
l.setItem(1, Py::Int((int)it.I2));
|
||||
line.append(l);
|
||||
}
|
||||
tuple.setItem(1, line);
|
||||
return Py::new_reference_to(tuple);
|
||||
}
|
||||
|
||||
PyObject* ComplexGeoDataPy::getPoints(PyObject *args)
|
||||
PyObject* ComplexGeoDataPy::getPoints(PyObject* args)
|
||||
{
|
||||
double accuracy = 0.05;
|
||||
if (!PyArg_ParseTuple(args, "d", &accuracy))
|
||||
if (!PyArg_ParseTuple(args, "d", &accuracy)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<Base::Vector3d> points;
|
||||
std::vector<Base::Vector3d> normals;
|
||||
@@ -167,24 +174,25 @@ PyObject* ComplexGeoDataPy::getPoints(PyObject *args)
|
||||
|
||||
Py::Tuple tuple(2);
|
||||
Py::List vertex;
|
||||
for (const auto & it : points) {
|
||||
for (const auto& it : points) {
|
||||
vertex.append(Py::asObject(new Base::VectorPy(it)));
|
||||
}
|
||||
tuple.setItem(0, vertex);
|
||||
|
||||
Py::List normal;
|
||||
for (const auto & it : normals) {
|
||||
for (const auto& it : normals) {
|
||||
normal.append(Py::asObject(new Base::VectorPy(it)));
|
||||
}
|
||||
tuple.setItem(1, normal);
|
||||
return Py::new_reference_to(tuple);
|
||||
}
|
||||
|
||||
PyObject* ComplexGeoDataPy::getLines(PyObject *args)
|
||||
PyObject* ComplexGeoDataPy::getLines(PyObject* args)
|
||||
{
|
||||
double accuracy = 0.05;
|
||||
if (!PyArg_ParseTuple(args, "d", &accuracy))
|
||||
if (!PyArg_ParseTuple(args, "d", &accuracy)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<Base::Vector3d> points;
|
||||
std::vector<Data::ComplexGeoData::Line> lines;
|
||||
@@ -198,25 +206,27 @@ PyObject* ComplexGeoDataPy::getLines(PyObject *args)
|
||||
|
||||
Py::Tuple tuple(2);
|
||||
Py::List vertex;
|
||||
for (const auto & it : points)
|
||||
for (const auto& it : points) {
|
||||
vertex.append(Py::asObject(new Base::VectorPy(it)));
|
||||
}
|
||||
tuple.setItem(0, vertex);
|
||||
Py::List line;
|
||||
for (const auto & it : lines) {
|
||||
for (const auto& it : lines) {
|
||||
Py::Tuple l(2);
|
||||
l.setItem(0,Py::Int((int)it.I1));
|
||||
l.setItem(1,Py::Int((int)it.I2));
|
||||
l.setItem(0, Py::Int((int)it.I1));
|
||||
l.setItem(1, Py::Int((int)it.I2));
|
||||
line.append(l);
|
||||
}
|
||||
tuple.setItem(1, line);
|
||||
return Py::new_reference_to(tuple);
|
||||
}
|
||||
|
||||
PyObject* ComplexGeoDataPy::getFaces(PyObject *args)
|
||||
PyObject* ComplexGeoDataPy::getFaces(PyObject* args)
|
||||
{
|
||||
double accuracy = 0.05;
|
||||
if (!PyArg_ParseTuple(args, "d", &accuracy))
|
||||
if (!PyArg_ParseTuple(args, "d", &accuracy)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<Base::Vector3d> points;
|
||||
std::vector<Data::ComplexGeoData::Facet> facets;
|
||||
@@ -230,26 +240,28 @@ PyObject* ComplexGeoDataPy::getFaces(PyObject *args)
|
||||
|
||||
Py::Tuple tuple(2);
|
||||
Py::List vertex;
|
||||
for (const auto & it : points)
|
||||
for (const auto& it : points) {
|
||||
vertex.append(Py::asObject(new Base::VectorPy(it)));
|
||||
}
|
||||
tuple.setItem(0, vertex);
|
||||
Py::List facet;
|
||||
for (const auto & it : facets) {
|
||||
for (const auto& it : facets) {
|
||||
Py::Tuple f(3);
|
||||
f.setItem(0,Py::Int((int)it.I1));
|
||||
f.setItem(1,Py::Int((int)it.I2));
|
||||
f.setItem(2,Py::Int((int)it.I3));
|
||||
f.setItem(0, Py::Int((int)it.I1));
|
||||
f.setItem(1, Py::Int((int)it.I2));
|
||||
f.setItem(2, Py::Int((int)it.I3));
|
||||
facet.append(f);
|
||||
}
|
||||
tuple.setItem(1, facet);
|
||||
return Py::new_reference_to(tuple);
|
||||
}
|
||||
|
||||
PyObject* ComplexGeoDataPy::applyTranslation(PyObject *args)
|
||||
PyObject* ComplexGeoDataPy::applyTranslation(PyObject* args)
|
||||
{
|
||||
PyObject *obj;
|
||||
if (!PyArg_ParseTuple(args, "O!", &(Base::VectorPy::Type),&obj))
|
||||
PyObject* obj;
|
||||
if (!PyArg_ParseTuple(args, "O!", &(Base::VectorPy::Type), &obj)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
Base::Vector3d move = static_cast<Base::VectorPy*>(obj)->value();
|
||||
@@ -262,11 +274,12 @@ PyObject* ComplexGeoDataPy::applyTranslation(PyObject *args)
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* ComplexGeoDataPy::applyRotation(PyObject *args)
|
||||
PyObject* ComplexGeoDataPy::applyRotation(PyObject* args)
|
||||
{
|
||||
PyObject *obj;
|
||||
if (!PyArg_ParseTuple(args, "O!", &(Base::RotationPy::Type),&obj))
|
||||
PyObject* obj;
|
||||
if (!PyArg_ParseTuple(args, "O!", &(Base::RotationPy::Type), &obj)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
Base::Rotation rot = static_cast<Base::RotationPy*>(obj)->value();
|
||||
@@ -279,11 +292,12 @@ PyObject* ComplexGeoDataPy::applyRotation(PyObject *args)
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* ComplexGeoDataPy::transformGeometry(PyObject *args)
|
||||
PyObject* ComplexGeoDataPy::transformGeometry(PyObject* args)
|
||||
{
|
||||
PyObject *obj;
|
||||
if (!PyArg_ParseTuple(args, "O!", &(Base::MatrixPy::Type),&obj))
|
||||
PyObject* obj;
|
||||
if (!PyArg_ParseTuple(args, "O!", &(Base::MatrixPy::Type), &obj)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
Base::Matrix4D mat = static_cast<Base::MatrixPy*>(obj)->value();
|
||||
@@ -377,17 +391,18 @@ PyObject* ComplexGeoDataPy::setElementName(PyObject* args, PyObject* kwds)
|
||||
PyObject* pySid = Py_None;
|
||||
PyObject* overwrite = Py_False;
|
||||
|
||||
const std::array<const char *,7> kwlist = {"element", "name", "postfix", "overwrite", "sid", "tag", nullptr};
|
||||
const std::array<const char*, 7> kwlist =
|
||||
{"element", "name", "postfix", "overwrite", "sid", "tag", nullptr};
|
||||
if (!Wrapped_ParseTupleAndKeywords(args,
|
||||
kwds,
|
||||
"s|sssOOi",
|
||||
kwlist,
|
||||
&element,
|
||||
&name,
|
||||
&postfix,
|
||||
&overwrite,
|
||||
&pySid,
|
||||
&tag)) {
|
||||
kwds,
|
||||
"s|sssOOi",
|
||||
kwlist,
|
||||
&element,
|
||||
&name,
|
||||
&postfix,
|
||||
&overwrite,
|
||||
&pySid,
|
||||
&tag)) {
|
||||
return NULL;
|
||||
}
|
||||
ElementIDRefs sids;
|
||||
@@ -529,8 +544,9 @@ Py::Object ComplexGeoDataPy::getBoundBox() const
|
||||
Py::Object ComplexGeoDataPy::getCenterOfGravity() const
|
||||
{
|
||||
Base::Vector3d center;
|
||||
if (getComplexGeoDataPtr()->getCenterOfGravity(center))
|
||||
if (getComplexGeoDataPtr()->getCenterOfGravity(center)) {
|
||||
return Py::Vector(center);
|
||||
}
|
||||
throw Py::RuntimeError("Cannot get center of gravity");
|
||||
}
|
||||
|
||||
|
||||
@@ -39,55 +39,60 @@ DocumentObjectExtension::DocumentObjectExtension()
|
||||
|
||||
DocumentObjectExtension::~DocumentObjectExtension() = default;
|
||||
|
||||
short int DocumentObjectExtension::extensionMustExecute() {
|
||||
short int DocumentObjectExtension::extensionMustExecute()
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
App::DocumentObjectExecReturn* DocumentObjectExtension::extensionExecute() {
|
||||
App::DocumentObjectExecReturn* DocumentObjectExtension::extensionExecute()
|
||||
{
|
||||
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
void DocumentObjectExtension::onExtendedSettingDocument() {
|
||||
void DocumentObjectExtension::onExtendedSettingDocument()
|
||||
{}
|
||||
|
||||
}
|
||||
void DocumentObjectExtension::onExtendedDocumentRestored()
|
||||
{}
|
||||
|
||||
void DocumentObjectExtension::onExtendedDocumentRestored() {
|
||||
void DocumentObjectExtension::onExtendedSetupObject()
|
||||
{}
|
||||
|
||||
}
|
||||
void DocumentObjectExtension::onExtendedUnsetupObject()
|
||||
{}
|
||||
|
||||
void DocumentObjectExtension::onExtendedSetupObject() {
|
||||
PyObject* DocumentObjectExtension::getExtensionPyObject()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DocumentObjectExtension::onExtendedUnsetupObject() {
|
||||
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectExtension::getExtensionPyObject() {
|
||||
|
||||
if (ExtensionPythonObject.is(Py::_None())){
|
||||
if (ExtensionPythonObject.is(Py::_None())) {
|
||||
// ref counter is set to 1
|
||||
ExtensionPythonObject = Py::Object(new DocumentObjectExtensionPy(this),true);
|
||||
ExtensionPythonObject = Py::Object(new DocumentObjectExtensionPy(this), true);
|
||||
}
|
||||
return Py::new_reference_to(ExtensionPythonObject);
|
||||
}
|
||||
|
||||
const DocumentObject* DocumentObjectExtension::getExtendedObject() const {
|
||||
const DocumentObject* DocumentObjectExtension::getExtendedObject() const
|
||||
{
|
||||
|
||||
assert(getExtendedContainer()->isDerivedFrom(DocumentObject::getClassTypeId()));
|
||||
return static_cast<const DocumentObject*>(getExtendedContainer());
|
||||
}
|
||||
|
||||
DocumentObject* DocumentObjectExtension::getExtendedObject() {
|
||||
DocumentObject* DocumentObjectExtension::getExtendedObject()
|
||||
{
|
||||
|
||||
assert(getExtendedContainer()->isDerivedFrom(DocumentObject::getClassTypeId()));
|
||||
return static_cast<DocumentObject*>(getExtendedContainer());
|
||||
}
|
||||
|
||||
bool DocumentObjectExtension::extensionGetSubObject(DocumentObject *&,
|
||||
const char *, PyObject **, Base::Matrix4D *, bool, int) const
|
||||
bool DocumentObjectExtension::extensionGetSubObject(DocumentObject*&,
|
||||
const char*,
|
||||
PyObject**,
|
||||
Base::Matrix4D*,
|
||||
bool,
|
||||
int) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -97,8 +102,11 @@ bool DocumentObjectExtension::extensionGetSubObjects(std::vector<std::string>&,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DocumentObjectExtension::extensionGetLinkedObject(
|
||||
DocumentObject *&, bool, Base::Matrix4D *, bool, int) const
|
||||
bool DocumentObjectExtension::extensionGetLinkedObject(DocumentObject*&,
|
||||
bool,
|
||||
Base::Matrix4D*,
|
||||
bool,
|
||||
int) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -26,10 +26,12 @@
|
||||
|
||||
#include "Extension.h"
|
||||
|
||||
namespace Base {
|
||||
namespace Base
|
||||
{
|
||||
class Matrix4D;
|
||||
}
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
class DocumentObject;
|
||||
class DocumentObjectExecReturn;
|
||||
|
||||
@@ -37,24 +39,23 @@ class DocumentObjectExecReturn;
|
||||
* @brief Extension with special document object calls
|
||||
*
|
||||
*/
|
||||
class AppExport DocumentObjectExtension : public App::Extension
|
||||
class AppExport DocumentObjectExtension: public App::Extension
|
||||
{
|
||||
|
||||
//The cass does not have properties itself, but it is important to provide the property access
|
||||
//functions. see cpp file for details
|
||||
// The cass does not have properties itself, but it is important to provide the property access
|
||||
// functions. see cpp file for details
|
||||
EXTENSION_PROPERTY_HEADER_WITH_OVERRIDE(App::DocumentObjectExtension);
|
||||
|
||||
public:
|
||||
DocumentObjectExtension();
|
||||
~DocumentObjectExtension() override;
|
||||
|
||||
DocumentObjectExtension ();
|
||||
~DocumentObjectExtension () override;
|
||||
|
||||
App::DocumentObject* getExtendedObject();
|
||||
App::DocumentObject* getExtendedObject();
|
||||
const App::DocumentObject* getExtendedObject() const;
|
||||
|
||||
//override if execution is necessary
|
||||
// override if execution is necessary
|
||||
virtual short extensionMustExecute();
|
||||
virtual App::DocumentObjectExecReturn *extensionExecute();
|
||||
virtual App::DocumentObjectExecReturn* extensionExecute();
|
||||
|
||||
|
||||
/// get called after setting the document
|
||||
@@ -70,36 +71,55 @@ public:
|
||||
|
||||
/// returns the type name of the ViewProviderExtension which is automatically attached
|
||||
/// to the viewprovider object when it is initiated
|
||||
virtual const char* getViewProviderExtensionName() const {return "";}
|
||||
virtual const char* getViewProviderExtensionName() const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
/** Get the sub object by name
|
||||
* @sa DocumentObject::getSubObject()
|
||||
*
|
||||
* @return Return turn if handled, the sub object is returned in \c ret
|
||||
*/
|
||||
virtual bool extensionGetSubObject(DocumentObject *&ret, const char *subname,
|
||||
PyObject **pyObj, Base::Matrix4D *mat, bool transform, int depth) const;
|
||||
virtual bool extensionGetSubObject(DocumentObject*& ret,
|
||||
const char* subname,
|
||||
PyObject** pyObj,
|
||||
Base::Matrix4D* mat,
|
||||
bool transform,
|
||||
int depth) const;
|
||||
|
||||
/** Get name references of all sub objects
|
||||
* @sa DocumentObject::getSubObjects()
|
||||
*
|
||||
* @return Return turn if handled, the sub object is returned in \c ret
|
||||
*/
|
||||
virtual bool extensionGetSubObjects(std::vector<std::string> &ret, int reason) const;
|
||||
virtual bool extensionGetSubObjects(std::vector<std::string>& ret, int reason) const;
|
||||
|
||||
/** Get the linked object
|
||||
* @sa DocumentObject::getLinkedObject()
|
||||
*
|
||||
* @return Return turn if handled, the linked object is returned in \c ret
|
||||
*/
|
||||
virtual bool extensionGetLinkedObject(DocumentObject *&ret, bool recursive,
|
||||
Base::Matrix4D *mat, bool transform, int depth) const;
|
||||
virtual bool extensionGetLinkedObject(DocumentObject*& ret,
|
||||
bool recursive,
|
||||
Base::Matrix4D* mat,
|
||||
bool transform,
|
||||
int depth) const;
|
||||
|
||||
virtual int extensionSetElementVisible(const char *, bool) {return -1;}
|
||||
virtual int extensionIsElementVisible(const char *) {return -1;}
|
||||
virtual bool extensionHasChildElement() const {return false;}
|
||||
virtual int extensionSetElementVisible(const char*, bool)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
virtual int extensionIsElementVisible(const char*)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
virtual bool extensionHasChildElement() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} //App
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_DOCUMENTOBJECTEXTENSION_H
|
||||
#endif // APP_DOCUMENTOBJECTEXTENSION_H
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="ExtensionPy"
|
||||
Name="DocumentObjectExtensionPy"
|
||||
TwinPointer="DocumentObjectExtension"
|
||||
Twin="DocumentObjectExtension"
|
||||
Include="App/DocumentObjectExtension.h"
|
||||
Namespace="App"
|
||||
FatherInclude="App/ExtensionPy.h"
|
||||
<PythonExport
|
||||
Father="ExtensionPy"
|
||||
Name="DocumentObjectExtensionPy"
|
||||
TwinPointer="DocumentObjectExtension"
|
||||
Twin="DocumentObjectExtension"
|
||||
Include="App/DocumentObjectExtension.h"
|
||||
Namespace="App"
|
||||
FatherInclude="App/ExtensionPy.h"
|
||||
FatherNamespace="App">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Stefan Troeger" EMail="stefantroeger@gmx.net" />
|
||||
|
||||
@@ -35,12 +35,12 @@ std::string DocumentObjectExtensionPy::representation() const
|
||||
return {"<document object extension>"};
|
||||
}
|
||||
|
||||
PyObject *DocumentObjectExtensionPy::getCustomAttributes(const char* /*attr*/) const
|
||||
PyObject* DocumentObjectExtensionPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int DocumentObjectExtensionPy::setCustomAttributes(const char* /*attr*/, PyObject * /*obj*/)
|
||||
int DocumentObjectExtensionPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -32,8 +32,11 @@ PROPERTY_SOURCE(App::DocumentObjectFileIncluded, App::DocumentObject)
|
||||
|
||||
DocumentObjectFileIncluded::DocumentObjectFileIncluded()
|
||||
{
|
||||
ADD_PROPERTY_TYPE(File,(nullptr),"",(App::PropertyType)(Prop_None),"File to include into Project File");
|
||||
ADD_PROPERTY_TYPE(File,
|
||||
(nullptr),
|
||||
"",
|
||||
(App::PropertyType)(Prop_None),
|
||||
"File to include into Project File");
|
||||
}
|
||||
|
||||
DocumentObjectFileIncluded::~DocumentObjectFileIncluded() = default;
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
namespace App
|
||||
{
|
||||
|
||||
class AppExport DocumentObjectFileIncluded : public DocumentObject
|
||||
class AppExport DocumentObjectFileIncluded: public DocumentObject
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(App::DocumentObjectFileIncluded);
|
||||
|
||||
@@ -42,16 +42,16 @@ public:
|
||||
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
const char* getViewProviderName() const override {
|
||||
const char* getViewProviderName() const override
|
||||
{
|
||||
return "Gui::ViewProviderDocumentObject";
|
||||
}
|
||||
|
||||
/// Properties
|
||||
PropertyFileIncluded File;
|
||||
|
||||
};
|
||||
|
||||
} //namespace App
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // APP_DOCUMENTOBJECTFILEINCLUDED_H
|
||||
#endif // APP_DOCUMENTOBJECTFILEINCLUDED_H
|
||||
|
||||
@@ -31,19 +31,22 @@ using namespace App;
|
||||
|
||||
PROPERTY_SOURCE_WITH_EXTENSIONS(App::DocumentObjectGroup, App::DocumentObject)
|
||||
|
||||
DocumentObjectGroup::DocumentObjectGroup(): DocumentObject(), GroupExtension() {
|
||||
DocumentObjectGroup::DocumentObjectGroup()
|
||||
: DocumentObject()
|
||||
, GroupExtension()
|
||||
{
|
||||
|
||||
GroupExtension::initExtension(this);
|
||||
_GroupTouched.setStatus(App::Property::Output,true);
|
||||
_GroupTouched.setStatus(App::Property::Output, true);
|
||||
}
|
||||
|
||||
DocumentObjectGroup::~DocumentObjectGroup() = default;
|
||||
|
||||
PyObject *DocumentObjectGroup::getPyObject()
|
||||
PyObject* DocumentObjectGroup::getPyObject()
|
||||
{
|
||||
if (PythonObject.is(Py::_None())){
|
||||
if (PythonObject.is(Py::_None())) {
|
||||
// ref counter is set to 1
|
||||
PythonObject = Py::Object(new DocumentObjectGroupPy(this),true);
|
||||
PythonObject = Py::Object(new DocumentObjectGroupPy(this), true);
|
||||
}
|
||||
return Py::new_reference_to(PythonObject);
|
||||
}
|
||||
@@ -51,17 +54,22 @@ PyObject *DocumentObjectGroup::getPyObject()
|
||||
|
||||
// Python feature ---------------------------------------------------------
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
|
||||
/// @cond DOXERR
|
||||
PROPERTY_SOURCE_TEMPLATE(App::DocumentObjectGroupPython, App::DocumentObjectGroup)
|
||||
template<> const char* App::DocumentObjectGroupPython::getViewProviderName() const {
|
||||
template<>
|
||||
const char* App::DocumentObjectGroupPython::getViewProviderName() const
|
||||
{
|
||||
return "Gui::ViewProviderDocumentObjectGroupPython";
|
||||
}
|
||||
template<> PyObject* App::DocumentObjectGroupPython::getPyObject() {
|
||||
template<>
|
||||
PyObject* App::DocumentObjectGroupPython::getPyObject()
|
||||
{
|
||||
if (PythonObject.is(Py::_None())) {
|
||||
// ref counter is set to 1
|
||||
PythonObject = Py::Object(new FeaturePythonPyT<App::DocumentObjectGroupPy>(this),true);
|
||||
PythonObject = Py::Object(new FeaturePythonPyT<App::DocumentObjectGroupPy>(this), true);
|
||||
}
|
||||
return Py::new_reference_to(PythonObject);
|
||||
}
|
||||
@@ -69,4 +77,4 @@ template<> PyObject* App::DocumentObjectGroupPython::getPyObject() {
|
||||
|
||||
// explicit template instantiation
|
||||
template class AppExport FeaturePythonT<App::DocumentObjectGroup>;
|
||||
}
|
||||
} // namespace App
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
namespace App
|
||||
{
|
||||
|
||||
class AppExport DocumentObjectGroup : public DocumentObject, public GroupExtension {
|
||||
class AppExport DocumentObjectGroup: public DocumentObject, public GroupExtension
|
||||
{
|
||||
|
||||
PROPERTY_HEADER_WITH_EXTENSIONS(App::DocumentObjectGroup);
|
||||
|
||||
@@ -42,17 +43,18 @@ public:
|
||||
~DocumentObjectGroup() override;
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
const char* getViewProviderName() const override {
|
||||
const char* getViewProviderName() const override
|
||||
{
|
||||
return "Gui::ViewProviderDocumentObjectGroup";
|
||||
}
|
||||
|
||||
PyObject *getPyObject() override;
|
||||
PyObject* getPyObject() override;
|
||||
};
|
||||
|
||||
using DocumentObjectGroupPython = App::FeaturePythonT<DocumentObjectGroup>;
|
||||
|
||||
|
||||
} //namespace App
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // APP_DOCUMENTOBJECTGROUP_H
|
||||
#endif // APP_DOCUMENTOBJECTGROUP_H
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="DocumentObjectPy"
|
||||
Name="DocumentObjectGroupPy"
|
||||
Twin="DocumentObjectGroup"
|
||||
TwinPointer="DocumentObjectGroup"
|
||||
Include="App/DocumentObjectGroup.h"
|
||||
Namespace="App"
|
||||
FatherInclude="App/DocumentObjectPy.h"
|
||||
<PythonExport
|
||||
Father="DocumentObjectPy"
|
||||
Name="DocumentObjectGroupPy"
|
||||
Twin="DocumentObjectGroup"
|
||||
TwinPointer="DocumentObjectGroup"
|
||||
Include="App/DocumentObjectGroup.h"
|
||||
Namespace="App"
|
||||
FatherInclude="App/DocumentObjectPy.h"
|
||||
FatherNamespace="App">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Werner Mayer" EMail="wmayer@users.sourceforge.net" />
|
||||
|
||||
@@ -37,7 +37,7 @@ std::string DocumentObjectGroupPy::representation() const
|
||||
return {"<group object>"};
|
||||
}
|
||||
|
||||
PyObject *DocumentObjectGroupPy::getCustomAttributes(const char* /*attr*/) const
|
||||
PyObject* DocumentObjectGroupPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
@@ -46,4 +46,3 @@ int DocumentObjectGroupPy::setCustomAttributes(const char* /*attr*/, PyObject* /
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="ExtensionContainerPy"
|
||||
Name="DocumentObjectPy"
|
||||
Twin="DocumentObject"
|
||||
TwinPointer="DocumentObject"
|
||||
Include="App/DocumentObject.h"
|
||||
Namespace="App"
|
||||
FatherInclude="App/ExtensionContainerPy.h"
|
||||
<PythonExport
|
||||
Father="ExtensionContainerPy"
|
||||
Name="DocumentObjectPy"
|
||||
Twin="DocumentObject"
|
||||
TwinPointer="DocumentObject"
|
||||
Include="App/DocumentObject.h"
|
||||
Namespace="App"
|
||||
FatherInclude="App/ExtensionContainerPy.h"
|
||||
FatherNamespace="App">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Juergen Riegel" EMail="FreeCAD@juergen-riegel.net" />
|
||||
@@ -95,7 +95,7 @@ referencing subobject.
|
||||
PyObject: return a python binding object for the (sub)object referenced in
|
||||
each 'subname' The actual type of 'PyObject' is implementation dependent.
|
||||
For Part::Feature compatible objects, this will be of type TopoShapePy and
|
||||
pre-transformed by accumulated transformation matrix along the object path.
|
||||
pre-transformed by accumulated transformation matrix along the object path.
|
||||
|
||||
DocObject: return the document object referenced in subname, if 'matrix' is
|
||||
None. Or, return a tuple (object, matrix) for each 'subname' and 'matrix' is
|
||||
@@ -168,15 +168,15 @@ Return -1 if element visibility is not supported or element not found, 0 if invi
|
||||
</Methode>
|
||||
<Methode Name="getParentGroup">
|
||||
<Documentation>
|
||||
<UserDocu>Returns the group the object is in or None if it is not part of a group.
|
||||
Note that an object can only be in a single group, hence only a single return
|
||||
<UserDocu>Returns the group the object is in or None if it is not part of a group.
|
||||
Note that an object can only be in a single group, hence only a single return
|
||||
value.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getParentGeoFeatureGroup">
|
||||
<Documentation>
|
||||
<UserDocu>Returns the GeoFeatureGroup, and hence the local coordinate system, the object
|
||||
is in or None if it is not part of a group. Note that an object can only be
|
||||
<UserDocu>Returns the GeoFeatureGroup, and hence the local coordinate system, the object
|
||||
is in or None if it is not part of a group. Note that an object can only be
|
||||
in a single group, hence only a single return value.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
|
||||
@@ -76,7 +76,7 @@ Py::Object DocumentObjectPy::getDocument() const
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::isAttachedToDocument(PyObject *args)
|
||||
PyObject* DocumentObjectPy::isAttachedToDocument(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
@@ -87,27 +87,52 @@ PyObject* DocumentObjectPy::isAttachedToDocument(PyObject *args)
|
||||
return Py::new_reference_to(Py::Boolean(ok));
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::addProperty(PyObject *args, PyObject *kwd)
|
||||
PyObject* DocumentObjectPy::addProperty(PyObject* args, PyObject* kwd)
|
||||
{
|
||||
char *sType,*sName=nullptr,*sGroup=nullptr,*sDoc=nullptr;
|
||||
short attr=0;
|
||||
char *sType, *sName = nullptr, *sGroup = nullptr, *sDoc = nullptr;
|
||||
short attr = 0;
|
||||
std::string sDocStr;
|
||||
PyObject *ro = Py_False, *hd = Py_False;
|
||||
PyObject* enumVals = nullptr;
|
||||
const std::array<const char *, 9> kwlist {"type","name","group","doc","attr","read_only","hidden","enum_vals",nullptr};
|
||||
if (!Base::Wrapped_ParseTupleAndKeywords(
|
||||
args, kwd, "ss|sethO!O!O", kwlist, &sType, &sName, &sGroup, "utf-8",
|
||||
&sDoc, &attr, &PyBool_Type, &ro, &PyBool_Type, &hd, &enumVals))
|
||||
const std::array<const char*, 9> kwlist {"type",
|
||||
"name",
|
||||
"group",
|
||||
"doc",
|
||||
"attr",
|
||||
"read_only",
|
||||
"hidden",
|
||||
"enum_vals",
|
||||
nullptr};
|
||||
if (!Base::Wrapped_ParseTupleAndKeywords(args,
|
||||
kwd,
|
||||
"ss|sethO!O!O",
|
||||
kwlist,
|
||||
&sType,
|
||||
&sName,
|
||||
&sGroup,
|
||||
"utf-8",
|
||||
&sDoc,
|
||||
&attr,
|
||||
&PyBool_Type,
|
||||
&ro,
|
||||
&PyBool_Type,
|
||||
&hd,
|
||||
&enumVals)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (sDoc) {
|
||||
sDocStr = sDoc;
|
||||
PyMem_Free(sDoc);
|
||||
}
|
||||
|
||||
Property *prop = getDocumentObjectPtr()->
|
||||
addDynamicProperty(sType,sName,sGroup,sDocStr.c_str(),attr,
|
||||
Base::asBoolean(ro), Base::asBoolean(hd));
|
||||
Property* prop = getDocumentObjectPtr()->addDynamicProperty(sType,
|
||||
sName,
|
||||
sGroup,
|
||||
sDocStr.c_str(),
|
||||
attr,
|
||||
Base::asBoolean(ro),
|
||||
Base::asBoolean(hd));
|
||||
|
||||
// enum support
|
||||
auto* propEnum = dynamic_cast<App::PropertyEnumeration*>(prop);
|
||||
@@ -118,26 +143,28 @@ PyObject* DocumentObjectPy::addProperty(PyObject *args, PyObject *kwd)
|
||||
return Py::new_reference_to(this);
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::removeProperty(PyObject *args)
|
||||
PyObject* DocumentObjectPy::removeProperty(PyObject* args)
|
||||
{
|
||||
char *sName;
|
||||
if (!PyArg_ParseTuple(args, "s", &sName))
|
||||
char* sName;
|
||||
if (!PyArg_ParseTuple(args, "s", &sName)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ok = getDocumentObjectPtr()->removeDynamicProperty(sName);
|
||||
return Py_BuildValue("O", (ok ? Py_True : Py_False));
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::supportedProperties(PyObject *args)
|
||||
PyObject* DocumentObjectPy::supportedProperties(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<Base::Type> ary;
|
||||
Base::Type::getAllDerivedFrom(App::Property::getClassTypeId(), ary);
|
||||
Py::List res;
|
||||
for (auto & it : ary) {
|
||||
Base::BaseClass *data = static_cast<Base::BaseClass*>(it.createInstance());
|
||||
for (auto& it : ary) {
|
||||
Base::BaseClass* data = static_cast<Base::BaseClass*>(it.createInstance());
|
||||
if (data) {
|
||||
delete data;
|
||||
res.append(Py::String(it.getName()));
|
||||
@@ -146,19 +173,21 @@ PyObject* DocumentObjectPy::supportedProperties(PyObject *args)
|
||||
return Py::new_reference_to(res);
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::touch(PyObject * args)
|
||||
PyObject* DocumentObjectPy::touch(PyObject* args)
|
||||
{
|
||||
char *propName = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "|s",&propName))
|
||||
char* propName = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "|s", &propName)) {
|
||||
return nullptr;
|
||||
if(propName) {
|
||||
if(!propName[0]) {
|
||||
}
|
||||
if (propName) {
|
||||
if (!propName[0]) {
|
||||
getDocumentObjectPtr()->touch(true);
|
||||
Py_Return;
|
||||
}
|
||||
auto prop = getDocumentObjectPtr()->getPropertyByName(propName);
|
||||
if(!prop)
|
||||
if (!prop) {
|
||||
throw Py::RuntimeError("Property not found");
|
||||
}
|
||||
prop->touch();
|
||||
Py_Return;
|
||||
}
|
||||
@@ -167,18 +196,20 @@ PyObject* DocumentObjectPy::touch(PyObject * args)
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::purgeTouched(PyObject * args)
|
||||
PyObject* DocumentObjectPy::purgeTouched(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
getDocumentObjectPtr()->purgeTouched();
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::enforceRecompute(PyObject * args)
|
||||
PyObject* DocumentObjectPy::enforceRecompute(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
getDocumentObjectPtr()->enforceRecompute();
|
||||
Py_Return;
|
||||
}
|
||||
@@ -207,13 +238,13 @@ Py::List DocumentObjectPy::getState() const
|
||||
uptodate = false;
|
||||
list.append(Py::String("Restore"));
|
||||
}
|
||||
if (object->testStatus(App::Expand)){
|
||||
if (object->testStatus(App::Expand)) {
|
||||
list.append(Py::String("Expanded"));
|
||||
}
|
||||
if (object->testStatus(App::PartialObject)){
|
||||
if (object->testStatus(App::PartialObject)) {
|
||||
list.append(Py::String("Partial"));
|
||||
}
|
||||
if (object->testStatus(App::ObjImporting)){
|
||||
if (object->testStatus(App::ObjImporting)) {
|
||||
list.append(Py::String("Importing"));
|
||||
}
|
||||
if (uptodate) {
|
||||
@@ -225,7 +256,7 @@ Py::List DocumentObjectPy::getState() const
|
||||
Py::Object DocumentObjectPy::getViewObject() const
|
||||
{
|
||||
try {
|
||||
PyObject *dict = PySys_GetObject("modules");
|
||||
PyObject* dict = PySys_GetObject("modules");
|
||||
if (!dict) {
|
||||
return Py::None();
|
||||
}
|
||||
@@ -237,12 +268,13 @@ Py::Object DocumentObjectPy::getViewObject() const
|
||||
}
|
||||
|
||||
// double-check that the module doesn't have a null pointer
|
||||
Py::Module module(PyImport_ImportModule("FreeCADGui"),true);
|
||||
Py::Module module(PyImport_ImportModule("FreeCADGui"), true);
|
||||
if (module.isNull() || !module.hasAttr("getDocument")) {
|
||||
// in v0.14+, the GUI module can be loaded in console mode (but doesn't have all its document methods)
|
||||
// in v0.14+, the GUI module can be loaded in console mode (but doesn't have all its
|
||||
// document methods)
|
||||
return Py::None();
|
||||
}
|
||||
if(!getDocumentObjectPtr()->getDocument()) {
|
||||
if (!getDocumentObjectPtr()->getDocument()) {
|
||||
throw Py::RuntimeError("Object has no document");
|
||||
}
|
||||
const char* internalName = getDocumentObjectPtr()->getNameInDocument();
|
||||
@@ -266,7 +298,7 @@ Py::Object DocumentObjectPy::getViewObject() const
|
||||
return Py::None();
|
||||
}
|
||||
// FreeCADGui is loaded, so there must be wrong something else
|
||||
throw; // re-throw
|
||||
throw; // re-throw
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,8 +307,9 @@ Py::List DocumentObjectPy::getInList() const
|
||||
Py::List ret;
|
||||
std::vector<DocumentObject*> list = getDocumentObjectPtr()->getInList();
|
||||
|
||||
for (auto It : list)
|
||||
for (auto It : list) {
|
||||
ret.append(Py::Object(It->getPyObject(), true));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -287,8 +320,9 @@ Py::List DocumentObjectPy::getInListRecursive() const
|
||||
try {
|
||||
std::vector<DocumentObject*> list = getDocumentObjectPtr()->getInListRecursive();
|
||||
|
||||
for (auto It : list)
|
||||
for (auto It : list) {
|
||||
ret.append(Py::Object(It->getPyObject(), true));
|
||||
}
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
throw Py::IndexError(e.what());
|
||||
@@ -301,8 +335,9 @@ Py::List DocumentObjectPy::getOutList() const
|
||||
Py::List ret;
|
||||
std::vector<DocumentObject*> list = getDocumentObjectPtr()->getOutList();
|
||||
|
||||
for (auto It : list)
|
||||
for (auto It : list) {
|
||||
ret.append(Py::Object(It->getPyObject(), true));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -314,8 +349,9 @@ Py::List DocumentObjectPy::getOutListRecursive() const
|
||||
std::vector<DocumentObject*> list = getDocumentObjectPtr()->getOutListRecursive();
|
||||
|
||||
// create the python list for the output
|
||||
for (auto It : list)
|
||||
for (auto It : list) {
|
||||
ret.append(Py::Object(It->getPyObject(), true));
|
||||
}
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
throw Py::IndexError(e.what());
|
||||
@@ -324,14 +360,15 @@ Py::List DocumentObjectPy::getOutListRecursive() const
|
||||
return ret;
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::setExpression(PyObject * args)
|
||||
PyObject* DocumentObjectPy::setExpression(PyObject* args)
|
||||
{
|
||||
char * path = nullptr;
|
||||
PyObject * expr;
|
||||
char * comment = nullptr;
|
||||
char* path = nullptr;
|
||||
PyObject* expr;
|
||||
char* comment = nullptr;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "sO|s", &path, &expr, &comment))
|
||||
if (!PyArg_ParseTuple(args, "sO|s", &path, &expr, &comment)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
App::ObjectIdentifier p(ObjectIdentifier::parse(getDocumentObjectPtr(), path));
|
||||
|
||||
@@ -340,10 +377,11 @@ PyObject* DocumentObjectPy::setExpression(PyObject * args)
|
||||
Py_Return;
|
||||
}
|
||||
else if (PyUnicode_Check(expr)) {
|
||||
const char * exprStr = PyUnicode_AsUTF8(expr);
|
||||
const char* exprStr = PyUnicode_AsUTF8(expr);
|
||||
std::shared_ptr<Expression> shared_expr(Expression::parse(getDocumentObjectPtr(), exprStr));
|
||||
if (shared_expr && comment)
|
||||
if (shared_expr && comment) {
|
||||
shared_expr->comment = comment;
|
||||
}
|
||||
|
||||
getDocumentObjectPtr()->setExpression(p, shared_expr);
|
||||
Py_Return;
|
||||
@@ -352,22 +390,24 @@ PyObject* DocumentObjectPy::setExpression(PyObject * args)
|
||||
throw Py::TypeError("String or None expected.");
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::clearExpression(PyObject * args)
|
||||
PyObject* DocumentObjectPy::clearExpression(PyObject* args)
|
||||
{
|
||||
char * path = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "s", &path))
|
||||
char* path = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "s", &path)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
App::ObjectIdentifier p(ObjectIdentifier::parse(getDocumentObjectPtr(), path));
|
||||
getDocumentObjectPtr()->clearExpression(p);
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::evalExpression(PyObject *self, PyObject * args)
|
||||
PyObject* DocumentObjectPy::evalExpression(PyObject* self, PyObject* args)
|
||||
{
|
||||
const char *expr;
|
||||
if (!PyArg_ParseTuple(args, "s", &expr))
|
||||
const char* expr;
|
||||
if (!PyArg_ParseTuple(args, "s", &expr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// HINT:
|
||||
// The standard behaviour of Python for class methods is to always pass the class
|
||||
@@ -385,19 +425,23 @@ PyObject* DocumentObjectPy::evalExpression(PyObject *self, PyObject * args)
|
||||
obj = static_cast<DocumentObjectPy*>(self)->getDocumentObjectPtr();
|
||||
}
|
||||
|
||||
PY_TRY {
|
||||
PY_TRY
|
||||
{
|
||||
std::shared_ptr<Expression> shared_expr(Expression::parse(obj, expr));
|
||||
if (shared_expr)
|
||||
if (shared_expr) {
|
||||
return Py::new_reference_to(shared_expr->getPyValue());
|
||||
}
|
||||
Py_Return;
|
||||
} PY_CATCH
|
||||
}
|
||||
PY_CATCH
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::recompute(PyObject *args)
|
||||
PyObject* DocumentObjectPy::recompute(PyObject* args)
|
||||
{
|
||||
PyObject *recursive = Py_False;
|
||||
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &recursive))
|
||||
PyObject* recursive = Py_False;
|
||||
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &recursive)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
bool ok = getDocumentObjectPtr()->recomputeFeature(Base::asBoolean(recursive));
|
||||
@@ -408,10 +452,11 @@ PyObject* DocumentObjectPy::recompute(PyObject *args)
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::isValid(PyObject *args)
|
||||
PyObject* DocumentObjectPy::isValid(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
bool ok = getDocumentObjectPtr()->isValid();
|
||||
@@ -422,10 +467,11 @@ PyObject* DocumentObjectPy::isValid(PyObject *args)
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::getStatusString(PyObject *args)
|
||||
PyObject* DocumentObjectPy::getStatusString(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
Py::String text(getDocumentObjectPtr()->getStatusString());
|
||||
@@ -436,9 +482,10 @@ PyObject* DocumentObjectPy::getStatusString(PyObject *args)
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds)
|
||||
PyObject* DocumentObjectPy::getSubObject(PyObject* args, PyObject* keywds)
|
||||
{
|
||||
enum class ReturnType {
|
||||
enum class ReturnType
|
||||
{
|
||||
PyObject = 0,
|
||||
DocObject = 1,
|
||||
DocAndPyObject = 2,
|
||||
@@ -448,19 +495,33 @@ PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds)
|
||||
LinkAndMatrix = 6
|
||||
};
|
||||
|
||||
PyObject *obj;
|
||||
PyObject* obj;
|
||||
short retType = 0;
|
||||
PyObject *pyMat = nullptr;
|
||||
PyObject *doTransform = Py_True;
|
||||
PyObject* pyMat = nullptr;
|
||||
PyObject* doTransform = Py_True;
|
||||
short depth = 0;
|
||||
|
||||
static const std::array<const char *, 6> kwlist {"subname", "retType", "matrix", "transform", "depth", nullptr};
|
||||
if (!Base::Wrapped_ParseTupleAndKeywords(args, keywds, "O|hO!O!h", kwlist, &obj, &retType, &Base::MatrixPy::Type,
|
||||
&pyMat, &PyBool_Type, &doTransform, &depth)) {
|
||||
static const std::array<const char*, 6> kwlist {"subname",
|
||||
"retType",
|
||||
"matrix",
|
||||
"transform",
|
||||
"depth",
|
||||
nullptr};
|
||||
if (!Base::Wrapped_ParseTupleAndKeywords(args,
|
||||
keywds,
|
||||
"O|hO!O!h",
|
||||
kwlist,
|
||||
&obj,
|
||||
&retType,
|
||||
&Base::MatrixPy::Type,
|
||||
&pyMat,
|
||||
&PyBool_Type,
|
||||
&doTransform,
|
||||
&depth)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (retType < 0 || static_cast<size_t> (retType) > kwlist.size()) {
|
||||
if (retType < 0 || static_cast<size_t>(retType) > kwlist.size()) {
|
||||
PyErr_SetString(PyExc_ValueError, "invalid retType, can only be integer 0~6");
|
||||
return nullptr;
|
||||
}
|
||||
@@ -493,12 +554,15 @@ PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds)
|
||||
|
||||
bool transform = Base::asBoolean(doTransform);
|
||||
|
||||
struct SubInfo {
|
||||
App::DocumentObject *sobj{nullptr};
|
||||
struct SubInfo
|
||||
{
|
||||
App::DocumentObject* sobj {nullptr};
|
||||
Py::Object obj;
|
||||
Py::Object pyObj;
|
||||
Base::Matrix4D mat;
|
||||
explicit SubInfo(const Base::Matrix4D &mat) : mat(mat){}
|
||||
explicit SubInfo(const Base::Matrix4D& mat)
|
||||
: mat(mat)
|
||||
{}
|
||||
};
|
||||
|
||||
Base::Matrix4D mat;
|
||||
@@ -506,50 +570,66 @@ PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds)
|
||||
mat = *static_cast<Base::MatrixPy*>(pyMat)->getMatrixPtr();
|
||||
}
|
||||
|
||||
PY_TRY {
|
||||
PY_TRY
|
||||
{
|
||||
std::vector<SubInfo> ret;
|
||||
for(const auto &sub : subs) {
|
||||
for (const auto& sub : subs) {
|
||||
ret.emplace_back(mat);
|
||||
auto &info = ret.back();
|
||||
PyObject *pyObj = nullptr;
|
||||
auto& info = ret.back();
|
||||
PyObject* pyObj = nullptr;
|
||||
|
||||
info.sobj = getDocumentObjectPtr()->getSubObject(sub.c_str(),
|
||||
retEnum != ReturnType::PyObject &&
|
||||
retEnum != ReturnType::DocAndPyObject ? nullptr : &pyObj,
|
||||
&info.mat, transform, depth);
|
||||
if (pyObj)
|
||||
info.sobj = getDocumentObjectPtr()->getSubObject(
|
||||
sub.c_str(),
|
||||
retEnum != ReturnType::PyObject && retEnum != ReturnType::DocAndPyObject ? nullptr
|
||||
: &pyObj,
|
||||
&info.mat,
|
||||
transform,
|
||||
depth);
|
||||
if (pyObj) {
|
||||
info.pyObj = Py::asObject(pyObj);
|
||||
if (info.sobj)
|
||||
}
|
||||
if (info.sobj) {
|
||||
info.obj = Py::asObject(info.sobj->getPyObject());
|
||||
}
|
||||
}
|
||||
|
||||
if (ret.empty())
|
||||
if (ret.empty()) {
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
auto getReturnValue = [retEnum, pyMat](SubInfo& ret) -> Py::Object {
|
||||
if (retEnum == ReturnType::PyObject)
|
||||
if (retEnum == ReturnType::PyObject) {
|
||||
return ret.pyObj;
|
||||
else if (retEnum == ReturnType::DocObject && !pyMat)
|
||||
}
|
||||
else if (retEnum == ReturnType::DocObject && !pyMat) {
|
||||
return ret.obj;
|
||||
else if (!ret.sobj)
|
||||
}
|
||||
else if (!ret.sobj) {
|
||||
return Py::None();
|
||||
else if (retEnum == ReturnType::Placement)
|
||||
}
|
||||
else if (retEnum == ReturnType::Placement) {
|
||||
return Py::Placement(Base::Placement(ret.mat));
|
||||
else if (retEnum == ReturnType::Matrix)
|
||||
}
|
||||
else if (retEnum == ReturnType::Matrix) {
|
||||
return Py::Matrix(ret.mat);
|
||||
else if (retEnum == ReturnType::LinkAndPlacement || retEnum == ReturnType::LinkAndMatrix) {
|
||||
}
|
||||
else if (retEnum == ReturnType::LinkAndPlacement
|
||||
|| retEnum == ReturnType::LinkAndMatrix) {
|
||||
ret.sobj->getLinkedObject(true, &ret.mat, false);
|
||||
if (retEnum == ReturnType::LinkAndPlacement)
|
||||
if (retEnum == ReturnType::LinkAndPlacement) {
|
||||
return Py::Placement(Base::Placement(ret.mat));
|
||||
else
|
||||
}
|
||||
else {
|
||||
return Py::Matrix(ret.mat);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Py::Tuple rret(retEnum == ReturnType::DocObject ? 2 : 3);
|
||||
rret.setItem(0, ret.obj);
|
||||
rret.setItem(1, Py::asObject(new Base::MatrixPy(ret.mat)));
|
||||
if (retEnum != ReturnType::DocObject)
|
||||
if (retEnum != ReturnType::DocObject) {
|
||||
rret.setItem(2, ret.pyObj);
|
||||
}
|
||||
return rret;
|
||||
}
|
||||
};
|
||||
@@ -559,7 +639,7 @@ PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds)
|
||||
}
|
||||
|
||||
Py::Tuple tuple(ret.size());
|
||||
for(size_t i=0; i<ret.size(); ++i) {
|
||||
for (size_t i = 0; i < ret.size(); ++i) {
|
||||
tuple.setItem(i, getReturnValue(ret[i]));
|
||||
}
|
||||
return Py::new_reference_to(tuple);
|
||||
@@ -567,62 +647,90 @@ PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds)
|
||||
PY_CATCH
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::getSubObjectList(PyObject *args) {
|
||||
const char *subname;
|
||||
if (!PyArg_ParseTuple(args, "s", &subname))
|
||||
return nullptr;
|
||||
Py::List res;
|
||||
PY_TRY {
|
||||
for(auto o : getDocumentObjectPtr()->getSubObjectList(subname))
|
||||
res.append(Py::asObject(o->getPyObject()));
|
||||
return Py::new_reference_to(res);
|
||||
}PY_CATCH
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::getSubObjects(PyObject *args) {
|
||||
int reason = 0;
|
||||
if (!PyArg_ParseTuple(args, "|i", &reason))
|
||||
return nullptr;
|
||||
|
||||
PY_TRY {
|
||||
auto names = getDocumentObjectPtr()->getSubObjects(reason);
|
||||
Py::Tuple pyObjs(names.size());
|
||||
for(size_t i=0;i<names.size();++i)
|
||||
pyObjs.setItem(i,Py::String(names[i]));
|
||||
return Py::new_reference_to(pyObjs);
|
||||
}PY_CATCH;
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::getLinkedObject(PyObject *args, PyObject *keywds)
|
||||
PyObject* DocumentObjectPy::getSubObjectList(PyObject* args)
|
||||
{
|
||||
PyObject *recursive = Py_True;
|
||||
PyObject *pyMat = Py_None;
|
||||
PyObject *transform = Py_True;
|
||||
short depth = 0;
|
||||
static const std::array<const char *, 5> kwlist {"recursive","matrix","transform","depth", nullptr};
|
||||
if (!Base::Wrapped_ParseTupleAndKeywords(args, keywds, "|O!OO!h", kwlist,
|
||||
&PyBool_Type, &recursive, &pyMat, &PyBool_Type, &transform, &depth)) {
|
||||
const char* subname;
|
||||
if (!PyArg_ParseTuple(args, "s", &subname)) {
|
||||
return nullptr;
|
||||
}
|
||||
Py::List res;
|
||||
PY_TRY
|
||||
{
|
||||
for (auto o : getDocumentObjectPtr()->getSubObjectList(subname)) {
|
||||
res.append(Py::asObject(o->getPyObject()));
|
||||
}
|
||||
return Py::new_reference_to(res);
|
||||
}
|
||||
PY_CATCH
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::getSubObjects(PyObject* args)
|
||||
{
|
||||
int reason = 0;
|
||||
if (!PyArg_ParseTuple(args, "|i", &reason)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PY_TRY {
|
||||
Base::PyTypeCheck(&pyMat, &Base::MatrixPy::Type, "expect argument 'matrix' to be of type Base.Matrix");
|
||||
PY_TRY
|
||||
{
|
||||
auto names = getDocumentObjectPtr()->getSubObjects(reason);
|
||||
Py::Tuple pyObjs(names.size());
|
||||
for (size_t i = 0; i < names.size(); ++i) {
|
||||
pyObjs.setItem(i, Py::String(names[i]));
|
||||
}
|
||||
return Py::new_reference_to(pyObjs);
|
||||
}
|
||||
PY_CATCH;
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::getLinkedObject(PyObject* args, PyObject* keywds)
|
||||
{
|
||||
PyObject* recursive = Py_True;
|
||||
PyObject* pyMat = Py_None;
|
||||
PyObject* transform = Py_True;
|
||||
short depth = 0;
|
||||
static const std::array<const char*, 5> kwlist {"recursive",
|
||||
"matrix",
|
||||
"transform",
|
||||
"depth",
|
||||
nullptr};
|
||||
if (!Base::Wrapped_ParseTupleAndKeywords(args,
|
||||
keywds,
|
||||
"|O!OO!h",
|
||||
kwlist,
|
||||
&PyBool_Type,
|
||||
&recursive,
|
||||
&pyMat,
|
||||
&PyBool_Type,
|
||||
&transform,
|
||||
&depth)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PY_TRY
|
||||
{
|
||||
Base::PyTypeCheck(&pyMat,
|
||||
&Base::MatrixPy::Type,
|
||||
"expect argument 'matrix' to be of type Base.Matrix");
|
||||
Base::Matrix4D _mat;
|
||||
Base::Matrix4D *mat = nullptr;
|
||||
Base::Matrix4D* mat = nullptr;
|
||||
if (pyMat) {
|
||||
_mat = *static_cast<Base::MatrixPy*>(pyMat)->getMatrixPtr();
|
||||
mat = &_mat;
|
||||
}
|
||||
|
||||
auto linked = getDocumentObjectPtr()->getLinkedObject(
|
||||
Base::asBoolean(recursive), mat, Base::asBoolean(transform), depth);
|
||||
if (!linked)
|
||||
auto linked = getDocumentObjectPtr()->getLinkedObject(Base::asBoolean(recursive),
|
||||
mat,
|
||||
Base::asBoolean(transform),
|
||||
depth);
|
||||
if (!linked) {
|
||||
linked = getDocumentObjectPtr();
|
||||
auto pyObj = Py::Object(linked->getPyObject(),true);
|
||||
}
|
||||
auto pyObj = Py::Object(linked->getPyObject(), true);
|
||||
if (mat) {
|
||||
Py::Tuple ret(2);
|
||||
ret.setItem(0,pyObj);
|
||||
ret.setItem(1,Py::asObject(new Base::MatrixPy(*mat)));
|
||||
ret.setItem(0, pyObj);
|
||||
ret.setItem(1, Py::asObject(new Base::MatrixPy(*mat)));
|
||||
return Py::new_reference_to(ret);
|
||||
}
|
||||
|
||||
@@ -631,44 +739,56 @@ PyObject* DocumentObjectPy::getLinkedObject(PyObject *args, PyObject *keywds)
|
||||
PY_CATCH;
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::isElementVisible(PyObject *args)
|
||||
PyObject* DocumentObjectPy::isElementVisible(PyObject* args)
|
||||
{
|
||||
char *element = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "s", &element))
|
||||
char* element = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "s", &element)) {
|
||||
return nullptr;
|
||||
PY_TRY {
|
||||
}
|
||||
PY_TRY
|
||||
{
|
||||
return Py_BuildValue("h", getDocumentObjectPtr()->isElementVisible(element));
|
||||
} PY_CATCH;
|
||||
}
|
||||
PY_CATCH;
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::setElementVisible(PyObject *args)
|
||||
PyObject* DocumentObjectPy::setElementVisible(PyObject* args)
|
||||
{
|
||||
char *element = nullptr;
|
||||
PyObject *visible = Py_True;
|
||||
if (!PyArg_ParseTuple(args, "s|O!", &element, &PyBool_Type, &visible))
|
||||
char* element = nullptr;
|
||||
PyObject* visible = Py_True;
|
||||
if (!PyArg_ParseTuple(args, "s|O!", &element, &PyBool_Type, &visible)) {
|
||||
return nullptr;
|
||||
PY_TRY {
|
||||
return Py_BuildValue("h", getDocumentObjectPtr()->setElementVisible(element, Base::asBoolean(visible)));
|
||||
} PY_CATCH;
|
||||
}
|
||||
PY_TRY
|
||||
{
|
||||
return Py_BuildValue(
|
||||
"h",
|
||||
getDocumentObjectPtr()->setElementVisible(element, Base::asBoolean(visible)));
|
||||
}
|
||||
PY_CATCH;
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::hasChildElement(PyObject *args)
|
||||
PyObject* DocumentObjectPy::hasChildElement(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
PY_TRY {
|
||||
return Py_BuildValue("O", getDocumentObjectPtr()->hasChildElement()?Py_True:Py_False);
|
||||
} PY_CATCH;
|
||||
}
|
||||
PY_TRY
|
||||
{
|
||||
return Py_BuildValue("O", getDocumentObjectPtr()->hasChildElement() ? Py_True : Py_False);
|
||||
}
|
||||
PY_CATCH;
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::getParentGroup(PyObject *args)
|
||||
PyObject* DocumentObjectPy::getParentGroup(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
auto grp = GroupExtension::getGroupOfObject(getDocumentObjectPtr());
|
||||
if(!grp) {
|
||||
if (!grp) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
@@ -679,14 +799,15 @@ PyObject* DocumentObjectPy::getParentGroup(PyObject *args)
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::getParentGeoFeatureGroup(PyObject *args)
|
||||
PyObject* DocumentObjectPy::getParentGeoFeatureGroup(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
auto grp = GeoFeatureGroupExtension::getGroupOfObject(getDocumentObjectPtr());
|
||||
if(!grp) {
|
||||
if (!grp) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
@@ -697,14 +818,15 @@ PyObject* DocumentObjectPy::getParentGeoFeatureGroup(PyObject *args)
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::getParent(PyObject *args)
|
||||
PyObject* DocumentObjectPy::getParent(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
auto grp = getDocumentObjectPtr()->getFirstParent();
|
||||
if(!grp) {
|
||||
if (!grp) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
@@ -725,15 +847,15 @@ Py::Boolean DocumentObjectPy::getMustExecute() const
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* DocumentObjectPy::getPathsByOutList(PyObject *args)
|
||||
PyObject* DocumentObjectPy::getPathsByOutList(PyObject* args)
|
||||
{
|
||||
PyObject* o;
|
||||
if (!PyArg_ParseTuple(args, "O!", &DocumentObjectPy::Type, &o))
|
||||
if (!PyArg_ParseTuple(args, "O!", &DocumentObjectPy::Type, &o)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
DocumentObject* target = static_cast<DocumentObjectPy*>
|
||||
(o)->getDocumentObjectPtr();
|
||||
DocumentObject* target = static_cast<DocumentObjectPy*>(o)->getDocumentObjectPtr();
|
||||
auto array = getDocumentObjectPtr()->getPathsByOutList(target);
|
||||
Py::List list;
|
||||
for (const auto& it : array) {
|
||||
@@ -766,100 +888,120 @@ PyObject* DocumentObjectPy::getElementMapVersion(PyObject* args)
|
||||
Py::String(getDocumentObjectPtr()->getElementMapVersion(prop, Base::asBoolean(restored))));
|
||||
}
|
||||
|
||||
PyObject *DocumentObjectPy::getCustomAttributes(const char* ) const
|
||||
PyObject* DocumentObjectPy::getCustomAttributes(const char*) const
|
||||
{
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
//remove
|
||||
int DocumentObjectPy::setCustomAttributes(const char* , PyObject *)
|
||||
// remove
|
||||
int DocumentObjectPy::setCustomAttributes(const char*, PyObject*)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Py::Int DocumentObjectPy::getID() const {
|
||||
Py::Int DocumentObjectPy::getID() const
|
||||
{
|
||||
return Py::Int(getDocumentObjectPtr()->getID());
|
||||
}
|
||||
|
||||
Py::Boolean DocumentObjectPy::getRemoving() const {
|
||||
Py::Boolean DocumentObjectPy::getRemoving() const
|
||||
{
|
||||
return {getDocumentObjectPtr()->testStatus(ObjectStatus::Remove)};
|
||||
}
|
||||
|
||||
PyObject *DocumentObjectPy::resolve(PyObject *args)
|
||||
PyObject* DocumentObjectPy::resolve(PyObject* args)
|
||||
{
|
||||
const char *subname;
|
||||
if (!PyArg_ParseTuple(args, "s",&subname))
|
||||
const char* subname;
|
||||
if (!PyArg_ParseTuple(args, "s", &subname)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PY_TRY {
|
||||
PY_TRY
|
||||
{
|
||||
std::string elementName;
|
||||
const char *subElement = nullptr;
|
||||
App::DocumentObject *parent = nullptr;
|
||||
auto obj = getDocumentObjectPtr()->resolve(subname,&parent,&elementName,&subElement);
|
||||
const char* subElement = nullptr;
|
||||
App::DocumentObject* parent = nullptr;
|
||||
auto obj = getDocumentObjectPtr()->resolve(subname, &parent, &elementName, &subElement);
|
||||
|
||||
Py::Tuple ret(4);
|
||||
ret.setItem(0,obj?Py::Object(obj->getPyObject(),true):Py::None());
|
||||
ret.setItem(1,parent?Py::Object(parent->getPyObject(),true):Py::None());
|
||||
ret.setItem(2,Py::String(elementName.c_str()));
|
||||
ret.setItem(3,Py::String(subElement?subElement:""));
|
||||
ret.setItem(0, obj ? Py::Object(obj->getPyObject(), true) : Py::None());
|
||||
ret.setItem(1, parent ? Py::Object(parent->getPyObject(), true) : Py::None());
|
||||
ret.setItem(2, Py::String(elementName.c_str()));
|
||||
ret.setItem(3, Py::String(subElement ? subElement : ""));
|
||||
return Py::new_reference_to(ret);
|
||||
} PY_CATCH;
|
||||
}
|
||||
PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject *DocumentObjectPy::resolveSubElement(PyObject *args)
|
||||
PyObject* DocumentObjectPy::resolveSubElement(PyObject* args)
|
||||
{
|
||||
const char *subname;
|
||||
PyObject *append = Py_False;
|
||||
const char* subname;
|
||||
PyObject* append = Py_False;
|
||||
int type = 0;
|
||||
if (!PyArg_ParseTuple(args, "s|O!i",&subname,&PyBool_Type,&append,&type))
|
||||
if (!PyArg_ParseTuple(args, "s|O!i", &subname, &PyBool_Type, &append, &type)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PY_TRY {
|
||||
PY_TRY
|
||||
{
|
||||
ElementNamePair elementName;
|
||||
auto obj = GeoFeature::resolveElement(getDocumentObjectPtr(), subname,elementName,
|
||||
Base::asBoolean(append), static_cast<GeoFeature::ElementNameType>(type));
|
||||
auto obj = GeoFeature::resolveElement(getDocumentObjectPtr(),
|
||||
subname,
|
||||
elementName,
|
||||
Base::asBoolean(append),
|
||||
static_cast<GeoFeature::ElementNameType>(type));
|
||||
Py::Tuple ret(3);
|
||||
ret.setItem(0,obj?Py::Object(obj->getPyObject(),true):Py::None());
|
||||
ret.setItem(1,Py::String(elementName.newName));
|
||||
ret.setItem(2,Py::String(elementName.oldName));
|
||||
ret.setItem(0, obj ? Py::Object(obj->getPyObject(), true) : Py::None());
|
||||
ret.setItem(1, Py::String(elementName.newName));
|
||||
ret.setItem(2, Py::String(elementName.oldName));
|
||||
return Py::new_reference_to(ret);
|
||||
} PY_CATCH;
|
||||
}
|
||||
PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
Py::List DocumentObjectPy::getParents() const {
|
||||
Py::List DocumentObjectPy::getParents() const
|
||||
{
|
||||
Py::List ret;
|
||||
for(auto &v : getDocumentObjectPtr()->getParents())
|
||||
ret.append(Py::TupleN(Py::Object(v.first->getPyObject(),true),Py::String(v.second)));
|
||||
for (auto& v : getDocumentObjectPtr()->getParents()) {
|
||||
ret.append(Py::TupleN(Py::Object(v.first->getPyObject(), true), Py::String(v.second)));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
PyObject *DocumentObjectPy::adjustRelativeLinks(PyObject *args) {
|
||||
PyObject *pyobj;
|
||||
PyObject *recursive = Py_True;
|
||||
if (!PyArg_ParseTuple(args, "O!|O",&DocumentObjectPy::Type,&pyobj,&recursive))
|
||||
PyObject* DocumentObjectPy::adjustRelativeLinks(PyObject* args)
|
||||
{
|
||||
PyObject* pyobj;
|
||||
PyObject* recursive = Py_True;
|
||||
if (!PyArg_ParseTuple(args, "O!|O", &DocumentObjectPy::Type, &pyobj, &recursive)) {
|
||||
return nullptr;
|
||||
PY_TRY {
|
||||
}
|
||||
PY_TRY
|
||||
{
|
||||
auto obj = static_cast<DocumentObjectPy*>(pyobj)->getDocumentObjectPtr();
|
||||
auto inList = obj->getInListEx(true);
|
||||
inList.insert(obj);
|
||||
std::set<App::DocumentObject *> visited;
|
||||
return Py::new_reference_to(Py::Boolean(
|
||||
getDocumentObjectPtr()->adjustRelativeLinks(inList,
|
||||
Base::asBoolean(recursive) ? &visited : nullptr)));
|
||||
}PY_CATCH
|
||||
std::set<App::DocumentObject*> visited;
|
||||
return Py::new_reference_to(Py::Boolean(getDocumentObjectPtr()->adjustRelativeLinks(
|
||||
inList,
|
||||
Base::asBoolean(recursive) ? &visited : nullptr)));
|
||||
}
|
||||
PY_CATCH
|
||||
}
|
||||
|
||||
Py::String DocumentObjectPy::getOldLabel() const {
|
||||
Py::String DocumentObjectPy::getOldLabel() const
|
||||
{
|
||||
return {getDocumentObjectPtr()->getOldLabel()};
|
||||
}
|
||||
|
||||
Py::Boolean DocumentObjectPy::getNoTouch() const {
|
||||
Py::Boolean DocumentObjectPy::getNoTouch() const
|
||||
{
|
||||
return {getDocumentObjectPtr()->testStatus(ObjectStatus::NoTouch)};
|
||||
}
|
||||
|
||||
void DocumentObjectPy::setNoTouch(Py::Boolean value) {
|
||||
getDocumentObjectPtr()->setStatus(ObjectStatus::NoTouch,value.isTrue());
|
||||
void DocumentObjectPy::setNoTouch(Py::Boolean value)
|
||||
{
|
||||
getDocumentObjectPtr()->setStatus(ObjectStatus::NoTouch, value.isTrue());
|
||||
}
|
||||
|
||||
@@ -57,8 +57,9 @@ DocumentT::~DocumentT() = default;
|
||||
|
||||
void DocumentT::operator=(const DocumentT& doc)
|
||||
{
|
||||
if (this == &doc)
|
||||
if (this == &doc) {
|
||||
return;
|
||||
}
|
||||
document = doc.document;
|
||||
}
|
||||
|
||||
@@ -77,7 +78,7 @@ Document* DocumentT::getDocument() const
|
||||
return GetApplication().getDocument(document.c_str());
|
||||
}
|
||||
|
||||
const std::string &DocumentT::getDocumentName() const
|
||||
const std::string& DocumentT::getDocumentName() const
|
||||
{
|
||||
return document;
|
||||
}
|
||||
@@ -93,12 +94,12 @@ std::string DocumentT::getDocumentPython() const
|
||||
|
||||
DocumentObjectT::DocumentObjectT() = default;
|
||||
|
||||
DocumentObjectT::DocumentObjectT(const DocumentObjectT &other)
|
||||
DocumentObjectT::DocumentObjectT(const DocumentObjectT& other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
DocumentObjectT::DocumentObjectT(DocumentObjectT &&other)
|
||||
DocumentObjectT::DocumentObjectT(DocumentObjectT&& other)
|
||||
{
|
||||
*this = std::move(other);
|
||||
}
|
||||
@@ -115,25 +116,29 @@ DocumentObjectT::DocumentObjectT(const Property* prop)
|
||||
|
||||
DocumentObjectT::DocumentObjectT(const Document* doc, const std::string& objName)
|
||||
{
|
||||
if (doc && doc->getName())
|
||||
if (doc && doc->getName()) {
|
||||
document = doc->getName();
|
||||
}
|
||||
object = objName;
|
||||
}
|
||||
|
||||
DocumentObjectT::DocumentObjectT(const char *docName, const char *objName)
|
||||
DocumentObjectT::DocumentObjectT(const char* docName, const char* objName)
|
||||
{
|
||||
if(docName)
|
||||
if (docName) {
|
||||
document = docName;
|
||||
if(objName)
|
||||
}
|
||||
if (objName) {
|
||||
object = objName;
|
||||
}
|
||||
}
|
||||
|
||||
DocumentObjectT::~DocumentObjectT() = default;
|
||||
|
||||
DocumentObjectT &DocumentObjectT::operator=(const DocumentObjectT& obj)
|
||||
DocumentObjectT& DocumentObjectT::operator=(const DocumentObjectT& obj)
|
||||
{
|
||||
if (this == &obj)
|
||||
if (this == &obj) {
|
||||
return *this;
|
||||
}
|
||||
object = obj.object;
|
||||
label = obj.label;
|
||||
document = obj.document;
|
||||
@@ -141,10 +146,11 @@ DocumentObjectT &DocumentObjectT::operator=(const DocumentObjectT& obj)
|
||||
return *this;
|
||||
}
|
||||
|
||||
DocumentObjectT &DocumentObjectT::operator=(DocumentObjectT&& obj)
|
||||
DocumentObjectT& DocumentObjectT::operator=(DocumentObjectT&& obj)
|
||||
{
|
||||
if (this == &obj)
|
||||
if (this == &obj) {
|
||||
return *this;
|
||||
}
|
||||
object = std::move(obj.object);
|
||||
label = std::move(obj.label);
|
||||
document = std::move(obj.document);
|
||||
@@ -154,12 +160,13 @@ DocumentObjectT &DocumentObjectT::operator=(DocumentObjectT&& obj)
|
||||
|
||||
void DocumentObjectT::operator=(const DocumentObject* obj)
|
||||
{
|
||||
if(!obj || !obj->isAttachedToDocument()) {
|
||||
if (!obj || !obj->isAttachedToDocument()) {
|
||||
object.clear();
|
||||
label.clear();
|
||||
document.clear();
|
||||
property.clear();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
object = obj->getNameInDocument();
|
||||
label = obj->Label.getValue();
|
||||
document = obj->getDocument()->getName();
|
||||
@@ -167,16 +174,16 @@ void DocumentObjectT::operator=(const DocumentObject* obj)
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentObjectT::operator=(const Property *prop) {
|
||||
if(!prop || !prop->hasName()
|
||||
|| !prop->getContainer()
|
||||
|| !prop->getContainer()->isDerivedFrom(App::DocumentObject::getClassTypeId()))
|
||||
{
|
||||
void DocumentObjectT::operator=(const Property* prop)
|
||||
{
|
||||
if (!prop || !prop->hasName() || !prop->getContainer()
|
||||
|| !prop->getContainer()->isDerivedFrom(App::DocumentObject::getClassTypeId())) {
|
||||
object.clear();
|
||||
label.clear();
|
||||
document.clear();
|
||||
property.clear();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
auto obj = static_cast<App::DocumentObject*>(prop->getContainer());
|
||||
object = obj->getNameInDocument();
|
||||
label = obj->Label.getValue();
|
||||
@@ -185,10 +192,9 @@ void DocumentObjectT::operator=(const Property *prop) {
|
||||
}
|
||||
}
|
||||
|
||||
bool DocumentObjectT::operator==(const DocumentObjectT &other) const {
|
||||
return document == other.document
|
||||
&& object == other.object
|
||||
&& label == other.label
|
||||
bool DocumentObjectT::operator==(const DocumentObjectT& other) const
|
||||
{
|
||||
return document == other.document && object == other.object && label == other.label
|
||||
&& property == other.property;
|
||||
}
|
||||
|
||||
@@ -219,12 +225,12 @@ DocumentObject* DocumentObjectT::getObject() const
|
||||
return obj;
|
||||
}
|
||||
|
||||
const std::string &DocumentObjectT::getObjectName() const
|
||||
const std::string& DocumentObjectT::getObjectName() const
|
||||
{
|
||||
return object;
|
||||
}
|
||||
|
||||
const std::string &DocumentObjectT::getObjectLabel() const
|
||||
const std::string& DocumentObjectT::getObjectLabel() const
|
||||
{
|
||||
return label;
|
||||
}
|
||||
@@ -236,7 +242,8 @@ std::string DocumentObjectT::getObjectPython() const
|
||||
return str.str();
|
||||
}
|
||||
|
||||
const std::string &DocumentObjectT::getPropertyName() const {
|
||||
const std::string& DocumentObjectT::getPropertyName() const
|
||||
{
|
||||
return property;
|
||||
}
|
||||
|
||||
@@ -244,15 +251,18 @@ std::string DocumentObjectT::getPropertyPython() const
|
||||
{
|
||||
std::stringstream str;
|
||||
str << getObjectPython();
|
||||
if (!property.empty())
|
||||
if (!property.empty()) {
|
||||
str << '.' << property;
|
||||
}
|
||||
return str.str();
|
||||
}
|
||||
|
||||
Property *DocumentObjectT::getProperty() const {
|
||||
Property* DocumentObjectT::getProperty() const
|
||||
{
|
||||
auto obj = getObject();
|
||||
if(obj)
|
||||
if (obj) {
|
||||
return obj->getPropertyByName(property.c_str());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -260,86 +270,95 @@ Property *DocumentObjectT::getProperty() const {
|
||||
|
||||
SubObjectT::SubObjectT() = default;
|
||||
|
||||
SubObjectT::SubObjectT(const SubObjectT &) = default;
|
||||
SubObjectT::SubObjectT(const SubObjectT&) = default;
|
||||
|
||||
SubObjectT::SubObjectT(SubObjectT &&other)
|
||||
:DocumentObjectT(std::move(other)), subname(std::move(other.subname))
|
||||
SubObjectT::SubObjectT(SubObjectT&& other)
|
||||
: DocumentObjectT(std::move(other))
|
||||
, subname(std::move(other.subname))
|
||||
{}
|
||||
|
||||
SubObjectT::SubObjectT(const DocumentObject* obj, const char* s)
|
||||
: DocumentObjectT(obj)
|
||||
, subname(s ? s : "")
|
||||
{}
|
||||
|
||||
SubObjectT::SubObjectT(const DocumentObject* obj)
|
||||
: DocumentObjectT(obj)
|
||||
{}
|
||||
|
||||
SubObjectT::SubObjectT(const DocumentObjectT& obj, const char* s)
|
||||
: DocumentObjectT(obj)
|
||||
, subname(s ? s : "")
|
||||
{}
|
||||
|
||||
SubObjectT::SubObjectT(const char* docName, const char* objName, const char* s)
|
||||
: DocumentObjectT(docName, objName)
|
||||
, subname(s ? s : "")
|
||||
{}
|
||||
|
||||
bool SubObjectT::operator<(const SubObjectT& other) const
|
||||
{
|
||||
}
|
||||
|
||||
SubObjectT::SubObjectT(const DocumentObject *obj, const char *s)
|
||||
:DocumentObjectT(obj),subname(s?s:"")
|
||||
{
|
||||
}
|
||||
|
||||
SubObjectT::SubObjectT(const DocumentObject *obj)
|
||||
:DocumentObjectT(obj)
|
||||
{
|
||||
}
|
||||
|
||||
SubObjectT::SubObjectT(const DocumentObjectT& obj, const char *s)
|
||||
:DocumentObjectT(obj),subname(s?s:"")
|
||||
{
|
||||
}
|
||||
|
||||
SubObjectT::SubObjectT(const char *docName, const char *objName, const char *s)
|
||||
:DocumentObjectT(docName,objName), subname(s?s:"")
|
||||
{
|
||||
}
|
||||
|
||||
bool SubObjectT::operator<(const SubObjectT &other) const {
|
||||
if(getDocumentName() < other.getDocumentName())
|
||||
if (getDocumentName() < other.getDocumentName()) {
|
||||
return true;
|
||||
if(getDocumentName() > other.getDocumentName())
|
||||
}
|
||||
if (getDocumentName() > other.getDocumentName()) {
|
||||
return false;
|
||||
if(getObjectName() < other.getObjectName())
|
||||
}
|
||||
if (getObjectName() < other.getObjectName()) {
|
||||
return true;
|
||||
if(getObjectName() > other.getObjectName())
|
||||
}
|
||||
if (getObjectName() > other.getObjectName()) {
|
||||
return false;
|
||||
if(getSubName() < other.getSubName())
|
||||
}
|
||||
if (getSubName() < other.getSubName()) {
|
||||
return true;
|
||||
if(getSubName() > other.getSubName())
|
||||
}
|
||||
if (getSubName() > other.getSubName()) {
|
||||
return false;
|
||||
}
|
||||
return getPropertyName() < other.getPropertyName();
|
||||
}
|
||||
|
||||
SubObjectT &SubObjectT::operator=(const SubObjectT& other)
|
||||
SubObjectT& SubObjectT::operator=(const SubObjectT& other)
|
||||
{
|
||||
if (this == &other)
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
static_cast<DocumentObjectT&>(*this) = other;
|
||||
subname = other.subname;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SubObjectT &SubObjectT::operator=(SubObjectT &&other)
|
||||
SubObjectT& SubObjectT::operator=(SubObjectT&& other)
|
||||
{
|
||||
if (this == &other)
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
static_cast<DocumentObjectT&>(*this) = std::move(other);
|
||||
subname = std::move(other.subname);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SubObjectT &SubObjectT::operator=(const DocumentObjectT &other)
|
||||
SubObjectT& SubObjectT::operator=(const DocumentObjectT& other)
|
||||
{
|
||||
if (this == &other)
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
static_cast<DocumentObjectT&>(*this) = other;
|
||||
subname.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SubObjectT &SubObjectT::operator=(const DocumentObject *other)
|
||||
SubObjectT& SubObjectT::operator=(const DocumentObject* other)
|
||||
{
|
||||
static_cast<DocumentObjectT&>(*this) = other;
|
||||
subname.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool SubObjectT::operator==(const SubObjectT &other) const {
|
||||
return static_cast<const DocumentObjectT&>(*this) == other
|
||||
&& subname == other.subname;
|
||||
bool SubObjectT::operator==(const SubObjectT& other) const
|
||||
{
|
||||
return static_cast<const DocumentObjectT&>(*this) == other && subname == other.subname;
|
||||
}
|
||||
|
||||
namespace
|
||||
@@ -430,19 +449,23 @@ SubObjectT App::SubObjectT::normalized(NormalizeOptions options) const
|
||||
return res;
|
||||
}
|
||||
|
||||
void SubObjectT::setSubName(const char *s) {
|
||||
subname = s?s:"";
|
||||
void SubObjectT::setSubName(const char* s)
|
||||
{
|
||||
subname = s ? s : "";
|
||||
}
|
||||
|
||||
const std::string &SubObjectT::getSubName() const {
|
||||
const std::string& SubObjectT::getSubName() const
|
||||
{
|
||||
return subname;
|
||||
}
|
||||
|
||||
std::string SubObjectT::getSubNameNoElement() const {
|
||||
std::string SubObjectT::getSubNameNoElement() const
|
||||
{
|
||||
return Data::noElementName(subname.c_str());
|
||||
}
|
||||
|
||||
const char *SubObjectT::getElementName() const {
|
||||
const char* SubObjectT::getElementName() const
|
||||
{
|
||||
return Data::findElementName(subname.c_str());
|
||||
}
|
||||
|
||||
@@ -457,90 +480,107 @@ bool SubObjectT::hasSubElement() const
|
||||
return element && (element[0] != '\0');
|
||||
}
|
||||
|
||||
std::string SubObjectT::getNewElementName() const {
|
||||
std::string SubObjectT::getNewElementName() const
|
||||
{
|
||||
ElementNamePair element;
|
||||
auto obj = getObject();
|
||||
if(!obj)
|
||||
if (!obj) {
|
||||
return {};
|
||||
GeoFeature::resolveElement(obj,subname.c_str(),element);
|
||||
}
|
||||
GeoFeature::resolveElement(obj, subname.c_str(), element);
|
||||
return std::move(element.newName);
|
||||
}
|
||||
|
||||
std::string SubObjectT::getOldElementName(int *index) const {
|
||||
std::string SubObjectT::getOldElementName(int* index) const
|
||||
{
|
||||
ElementNamePair element;
|
||||
auto obj = getObject();
|
||||
if(!obj)
|
||||
if (!obj) {
|
||||
return {};
|
||||
GeoFeature::resolveElement(obj,subname.c_str(),element);
|
||||
if(!index)
|
||||
}
|
||||
GeoFeature::resolveElement(obj, subname.c_str(), element);
|
||||
if (!index) {
|
||||
return std::move(element.oldName);
|
||||
}
|
||||
std::size_t pos = element.oldName.find_first_of("0123456789");
|
||||
if(pos == std::string::npos)
|
||||
if (pos == std::string::npos) {
|
||||
*index = -1;
|
||||
}
|
||||
else {
|
||||
*index = std::atoi(element.oldName.c_str()+pos);
|
||||
*index = std::atoi(element.oldName.c_str() + pos);
|
||||
element.oldName.resize(pos);
|
||||
}
|
||||
return std::move(element.oldName);
|
||||
}
|
||||
|
||||
App::DocumentObject *SubObjectT::getSubObject() const {
|
||||
App::DocumentObject* SubObjectT::getSubObject() const
|
||||
{
|
||||
auto obj = getObject();
|
||||
if(obj)
|
||||
if (obj) {
|
||||
return obj->getSubObject(subname.c_str());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string SubObjectT::getSubObjectPython(bool force) const {
|
||||
if(!force && subname.empty())
|
||||
std::string SubObjectT::getSubObjectPython(bool force) const
|
||||
{
|
||||
if (!force && subname.empty()) {
|
||||
return getObjectPython();
|
||||
}
|
||||
std::stringstream str;
|
||||
str << "(" << getObjectPython() << ",u'"
|
||||
<< Base::Tools::escapedUnicodeFromUtf8(subname.c_str()) << "')";
|
||||
str << "(" << getObjectPython() << ",u'" << Base::Tools::escapedUnicodeFromUtf8(subname.c_str())
|
||||
<< "')";
|
||||
return str.str();
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> SubObjectT::getSubObjectList() const {
|
||||
std::vector<App::DocumentObject*> SubObjectT::getSubObjectList() const
|
||||
{
|
||||
auto obj = getObject();
|
||||
if(obj)
|
||||
if (obj) {
|
||||
return obj->getSubObjectList(subname.c_str());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string SubObjectT::getObjectFullName(const char *docName) const
|
||||
std::string SubObjectT::getObjectFullName(const char* docName) const
|
||||
{
|
||||
std::ostringstream ss;
|
||||
if (!docName || getDocumentName() != docName) {
|
||||
ss << getDocumentName();
|
||||
if (auto doc = getDocument()) {
|
||||
if (doc->Label.getStrValue() != getDocumentName())
|
||||
if (doc->Label.getStrValue() != getDocumentName()) {
|
||||
ss << "(" << doc->Label.getValue() << ")";
|
||||
}
|
||||
}
|
||||
ss << "#";
|
||||
}
|
||||
ss << getObjectName();
|
||||
if (!getObjectLabel().empty() && getObjectLabel() != getObjectName())
|
||||
if (!getObjectLabel().empty() && getObjectLabel() != getObjectName()) {
|
||||
ss << " (" << getObjectLabel() << ")";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string SubObjectT::getSubObjectFullName(const char *docName) const
|
||||
std::string SubObjectT::getSubObjectFullName(const char* docName) const
|
||||
{
|
||||
if (subname.empty())
|
||||
if (subname.empty()) {
|
||||
return getObjectFullName(docName);
|
||||
}
|
||||
std::ostringstream ss;
|
||||
if (!docName || getDocumentName() != docName) {
|
||||
ss << getDocumentName();
|
||||
if (auto doc = getDocument()) {
|
||||
if (doc->Label.getStrValue() != getDocumentName())
|
||||
if (doc->Label.getStrValue() != getDocumentName()) {
|
||||
ss << "(" << doc->Label.getValue() << ")";
|
||||
}
|
||||
}
|
||||
ss << "#";
|
||||
}
|
||||
ss << getObjectName() << "." << subname;
|
||||
auto sobj = getSubObject();
|
||||
if (sobj && sobj->Label.getStrValue() != sobj->getNameInDocument())
|
||||
if (sobj && sobj->Label.getStrValue() != sobj->getNameInDocument()) {
|
||||
ss << " (" << sobj->Label.getValue() << ")";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
@@ -548,10 +588,9 @@ std::string SubObjectT::getSubObjectFullName(const char *docName) const
|
||||
|
||||
PropertyLinkT::PropertyLinkT()
|
||||
: toPython("None")
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
PropertyLinkT::PropertyLinkT(DocumentObject *obj)
|
||||
PropertyLinkT::PropertyLinkT(DocumentObject* obj)
|
||||
: PropertyLinkT()
|
||||
{
|
||||
if (obj) {
|
||||
@@ -563,15 +602,16 @@ PropertyLinkT::PropertyLinkT(DocumentObject *obj)
|
||||
}
|
||||
}
|
||||
|
||||
PropertyLinkT::PropertyLinkT(DocumentObject *obj, const std::vector<std::string>& subNames)
|
||||
PropertyLinkT::PropertyLinkT(DocumentObject* obj, const std::vector<std::string>& subNames)
|
||||
: PropertyLinkT()
|
||||
{
|
||||
if (obj) {
|
||||
std::ostringstream str;
|
||||
DocumentObjectT objT(obj);
|
||||
str << "(" << objT.getObjectPython() << ",[";
|
||||
for(const auto& it : subNames)
|
||||
for (const auto& it : subNames) {
|
||||
str << "'" << it << "',";
|
||||
}
|
||||
str << "])";
|
||||
|
||||
toPython = str.str();
|
||||
@@ -585,8 +625,9 @@ PropertyLinkT::PropertyLinkT(const std::vector<DocumentObject*>& objs)
|
||||
std::stringstream str;
|
||||
str << "[";
|
||||
for (std::size_t i = 0; i < objs.size(); i++) {
|
||||
if (i > 0)
|
||||
if (i > 0) {
|
||||
str << ", ";
|
||||
}
|
||||
|
||||
App::DocumentObject* obj = objs[i];
|
||||
if (obj) {
|
||||
@@ -602,17 +643,20 @@ PropertyLinkT::PropertyLinkT(const std::vector<DocumentObject*>& objs)
|
||||
}
|
||||
}
|
||||
|
||||
PropertyLinkT::PropertyLinkT(const std::vector<DocumentObject*>& objs, const std::vector<std::string>& subNames)
|
||||
PropertyLinkT::PropertyLinkT(const std::vector<DocumentObject*>& objs,
|
||||
const std::vector<std::string>& subNames)
|
||||
: PropertyLinkT()
|
||||
{
|
||||
if (!objs.empty() && objs.size() == subNames.size()) {
|
||||
std::stringstream str;
|
||||
str << "[";
|
||||
for (std::size_t i = 0; i < subNames.size(); i++) {
|
||||
if (i>0)
|
||||
if (i > 0) {
|
||||
str << ",(";
|
||||
else
|
||||
}
|
||||
else {
|
||||
str << "(";
|
||||
}
|
||||
|
||||
App::DocumentObject* obj = objs[i];
|
||||
if (obj) {
|
||||
@@ -639,22 +683,28 @@ std::string PropertyLinkT::getPropertyPython() const
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class DocumentWeakPtrT::Private {
|
||||
class DocumentWeakPtrT::Private
|
||||
{
|
||||
public:
|
||||
explicit Private(App::Document* doc) : _document(doc) {
|
||||
explicit Private(App::Document* doc)
|
||||
: _document(doc)
|
||||
{
|
||||
if (doc) {
|
||||
//NOLINTBEGIN
|
||||
connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(std::bind
|
||||
(&Private::deletedDocument, this, sp::_1));
|
||||
//NOLINTEND
|
||||
// NOLINTBEGIN
|
||||
connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(
|
||||
std::bind(&Private::deletedDocument, this, sp::_1));
|
||||
// NOLINTEND
|
||||
}
|
||||
}
|
||||
|
||||
void deletedDocument(const App::Document& doc) {
|
||||
if (_document == &doc)
|
||||
void deletedDocument(const App::Document& doc)
|
||||
{
|
||||
if (_document == &doc) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
void reset() {
|
||||
void reset()
|
||||
{
|
||||
connectApplicationDeletedDocument.disconnect();
|
||||
_document = nullptr;
|
||||
}
|
||||
@@ -665,9 +715,8 @@ public:
|
||||
};
|
||||
|
||||
DocumentWeakPtrT::DocumentWeakPtrT(App::Document* doc) noexcept
|
||||
: d(new Private(doc))
|
||||
{
|
||||
}
|
||||
: d(new Private(doc))
|
||||
{}
|
||||
|
||||
DocumentWeakPtrT::~DocumentWeakPtrT() = default;
|
||||
|
||||
@@ -693,56 +742,65 @@ App::Document* DocumentWeakPtrT::operator->() const noexcept
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class DocumentObjectWeakPtrT::Private {
|
||||
class DocumentObjectWeakPtrT::Private
|
||||
{
|
||||
public:
|
||||
explicit Private(App::DocumentObject* obj) : object(obj) {
|
||||
explicit Private(App::DocumentObject* obj)
|
||||
: object(obj)
|
||||
{
|
||||
set(obj);
|
||||
}
|
||||
void deletedDocument(const App::Document& doc) {
|
||||
void deletedDocument(const App::Document& doc)
|
||||
{
|
||||
// When deleting document then there is no way to undo it
|
||||
if (object && object->getDocument() == &doc) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
void createdObject(const App::DocumentObject& obj) noexcept {
|
||||
void createdObject(const App::DocumentObject& obj) noexcept
|
||||
{
|
||||
// When undoing the removal
|
||||
if (object == &obj) {
|
||||
indocument = true;
|
||||
}
|
||||
}
|
||||
void deletedObject(const App::DocumentObject& obj) noexcept {
|
||||
void deletedObject(const App::DocumentObject& obj) noexcept
|
||||
{
|
||||
if (object == &obj) {
|
||||
indocument = false;
|
||||
}
|
||||
}
|
||||
void reset() {
|
||||
void reset()
|
||||
{
|
||||
connectApplicationDeletedDocument.disconnect();
|
||||
connectDocumentCreatedObject.disconnect();
|
||||
connectDocumentDeletedObject.disconnect();
|
||||
object = nullptr;
|
||||
indocument = false;
|
||||
}
|
||||
void set(App::DocumentObject* obj) {
|
||||
void set(App::DocumentObject* obj)
|
||||
{
|
||||
object = obj;
|
||||
if (obj) {
|
||||
//NOLINTBEGIN
|
||||
// NOLINTBEGIN
|
||||
indocument = true;
|
||||
connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(std::bind
|
||||
(&Private::deletedDocument, this, sp::_1));
|
||||
connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(
|
||||
std::bind(&Private::deletedDocument, this, sp::_1));
|
||||
App::Document* doc = obj->getDocument();
|
||||
connectDocumentCreatedObject = doc->signalNewObject.connect(std::bind
|
||||
(&Private::createdObject, this, sp::_1));
|
||||
connectDocumentDeletedObject = doc->signalDeletedObject.connect(std::bind
|
||||
(&Private::deletedObject, this, sp::_1));
|
||||
//NOLINTEND
|
||||
connectDocumentCreatedObject =
|
||||
doc->signalNewObject.connect(std::bind(&Private::createdObject, this, sp::_1));
|
||||
connectDocumentDeletedObject =
|
||||
doc->signalDeletedObject.connect(std::bind(&Private::deletedObject, this, sp::_1));
|
||||
// NOLINTEND
|
||||
}
|
||||
}
|
||||
App::DocumentObject* get() const noexcept {
|
||||
App::DocumentObject* get() const noexcept
|
||||
{
|
||||
return indocument ? object : nullptr;
|
||||
}
|
||||
|
||||
App::DocumentObject* object;
|
||||
bool indocument{false};
|
||||
bool indocument {false};
|
||||
using Connection = boost::signals2::scoped_connection;
|
||||
Connection connectApplicationDeletedDocument;
|
||||
Connection connectDocumentCreatedObject;
|
||||
@@ -750,9 +808,8 @@ public:
|
||||
};
|
||||
|
||||
DocumentObjectWeakPtrT::DocumentObjectWeakPtrT(App::DocumentObject* obj)
|
||||
: d(new Private(obj))
|
||||
{
|
||||
}
|
||||
: d(new Private(obj))
|
||||
{}
|
||||
|
||||
DocumentObjectWeakPtrT::~DocumentObjectWeakPtrT() = default;
|
||||
|
||||
@@ -771,7 +828,7 @@ bool DocumentObjectWeakPtrT::expired() const noexcept
|
||||
return !d->indocument;
|
||||
}
|
||||
|
||||
DocumentObjectWeakPtrT& DocumentObjectWeakPtrT::operator= (App::DocumentObject* p)
|
||||
DocumentObjectWeakPtrT& DocumentObjectWeakPtrT::operator=(App::DocumentObject* p)
|
||||
{
|
||||
d->reset();
|
||||
d->set(p);
|
||||
@@ -788,31 +845,33 @@ App::DocumentObject* DocumentObjectWeakPtrT::operator->() const noexcept
|
||||
return d->get();
|
||||
}
|
||||
|
||||
bool DocumentObjectWeakPtrT::operator== (const DocumentObjectWeakPtrT& p) const noexcept
|
||||
bool DocumentObjectWeakPtrT::operator==(const DocumentObjectWeakPtrT& p) const noexcept
|
||||
{
|
||||
return d->get() == p.d->get();
|
||||
}
|
||||
|
||||
bool DocumentObjectWeakPtrT::operator!= (const DocumentObjectWeakPtrT& p) const noexcept
|
||||
bool DocumentObjectWeakPtrT::operator!=(const DocumentObjectWeakPtrT& p) const noexcept
|
||||
{
|
||||
return d->get() != p.d->get();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
DocumentObserver::DocumentObserver() : _document(nullptr)
|
||||
DocumentObserver::DocumentObserver()
|
||||
: _document(nullptr)
|
||||
{
|
||||
//NOLINTBEGIN
|
||||
this->connectApplicationCreatedDocument = App::GetApplication().signalNewDocument.connect(std::bind
|
||||
(&DocumentObserver::slotCreatedDocument, this, sp::_1));
|
||||
this->connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(std::bind
|
||||
(&DocumentObserver::slotDeletedDocument, this, sp::_1));
|
||||
this->connectApplicationActivateDocument = App::GetApplication().signalActiveDocument.connect(std::bind
|
||||
(&DocumentObserver::slotActivateDocument, this, sp::_1));
|
||||
//NOLINTEND
|
||||
// NOLINTBEGIN
|
||||
this->connectApplicationCreatedDocument = App::GetApplication().signalNewDocument.connect(
|
||||
std::bind(&DocumentObserver::slotCreatedDocument, this, sp::_1));
|
||||
this->connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(
|
||||
std::bind(&DocumentObserver::slotDeletedDocument, this, sp::_1));
|
||||
this->connectApplicationActivateDocument = App::GetApplication().signalActiveDocument.connect(
|
||||
std::bind(&DocumentObserver::slotActivateDocument, this, sp::_1));
|
||||
// NOLINTEND
|
||||
}
|
||||
|
||||
DocumentObserver::DocumentObserver(Document* doc) : DocumentObserver()
|
||||
DocumentObserver::DocumentObserver(Document* doc)
|
||||
: DocumentObserver()
|
||||
{
|
||||
// Connect to application and given document
|
||||
attachDocument(doc);
|
||||
@@ -838,18 +897,18 @@ void DocumentObserver::attachDocument(Document* doc)
|
||||
detachDocument();
|
||||
_document = doc;
|
||||
|
||||
//NOLINTBEGIN
|
||||
this->connectDocumentCreatedObject = _document->signalNewObject.connect(std::bind
|
||||
(&DocumentObserver::slotCreatedObject, this, sp::_1));
|
||||
this->connectDocumentDeletedObject = _document->signalDeletedObject.connect(std::bind
|
||||
(&DocumentObserver::slotDeletedObject, this, sp::_1));
|
||||
this->connectDocumentChangedObject = _document->signalChangedObject.connect(std::bind
|
||||
(&DocumentObserver::slotChangedObject, this, sp::_1, sp::_2));
|
||||
this->connectDocumentRecomputedObject = _document->signalRecomputedObject.connect(std::bind
|
||||
(&DocumentObserver::slotRecomputedObject, this, sp::_1));
|
||||
this->connectDocumentRecomputed = _document->signalRecomputed.connect(std::bind
|
||||
(&DocumentObserver::slotRecomputedDocument, this, sp::_1));
|
||||
//NOLINTEND
|
||||
// NOLINTBEGIN
|
||||
this->connectDocumentCreatedObject = _document->signalNewObject.connect(
|
||||
std::bind(&DocumentObserver::slotCreatedObject, this, sp::_1));
|
||||
this->connectDocumentDeletedObject = _document->signalDeletedObject.connect(
|
||||
std::bind(&DocumentObserver::slotDeletedObject, this, sp::_1));
|
||||
this->connectDocumentChangedObject = _document->signalChangedObject.connect(
|
||||
std::bind(&DocumentObserver::slotChangedObject, this, sp::_1, sp::_2));
|
||||
this->connectDocumentRecomputedObject = _document->signalRecomputedObject.connect(
|
||||
std::bind(&DocumentObserver::slotRecomputedObject, this, sp::_1));
|
||||
this->connectDocumentRecomputed = _document->signalRecomputed.connect(
|
||||
std::bind(&DocumentObserver::slotRecomputedDocument, this, sp::_1));
|
||||
// NOLINTEND
|
||||
}
|
||||
}
|
||||
|
||||
@@ -866,36 +925,29 @@ void DocumentObserver::detachDocument()
|
||||
}
|
||||
|
||||
void DocumentObserver::slotCreatedDocument(const App::Document& /*Doc*/)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
void DocumentObserver::slotDeletedDocument(const App::Document& /*Doc*/)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
void DocumentObserver::slotActivateDocument(const App::Document& /*Doc*/)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
void DocumentObserver::slotCreatedObject(const App::DocumentObject& /*Obj*/)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
void DocumentObserver::slotDeletedObject(const App::DocumentObject& /*Obj*/)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
void DocumentObserver::slotChangedObject(const App::DocumentObject& /*Obj*/, const App::Property& /*Prop*/)
|
||||
{
|
||||
}
|
||||
void DocumentObserver::slotChangedObject(const App::DocumentObject& /*Obj*/,
|
||||
const App::Property& /*Prop*/)
|
||||
{}
|
||||
|
||||
void DocumentObserver::slotRecomputedObject(const DocumentObject& /*Obj*/)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
void DocumentObserver::slotRecomputedDocument(const Document& /*doc*/)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -925,8 +977,7 @@ void DocumentObjectObserver::removeFromObservation(App::DocumentObject* obj)
|
||||
}
|
||||
|
||||
void DocumentObjectObserver::slotCreatedDocument(const App::Document&)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
void DocumentObjectObserver::slotDeletedDocument(const App::Document& Doc)
|
||||
{
|
||||
@@ -938,24 +989,22 @@ void DocumentObjectObserver::slotDeletedDocument(const App::Document& Doc)
|
||||
}
|
||||
|
||||
void DocumentObjectObserver::slotCreatedObject(const App::DocumentObject&)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
void DocumentObjectObserver::slotDeletedObject(const App::DocumentObject& Obj)
|
||||
{
|
||||
std::set<App::DocumentObject*>::iterator it = _objects.find
|
||||
(const_cast<App::DocumentObject*>(&Obj));
|
||||
if (it != _objects.end())
|
||||
std::set<App::DocumentObject*>::iterator it =
|
||||
_objects.find(const_cast<App::DocumentObject*>(&Obj));
|
||||
if (it != _objects.end()) {
|
||||
_objects.erase(it);
|
||||
if (_objects.empty())
|
||||
}
|
||||
if (_objects.empty()) {
|
||||
cancelObservation();
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentObjectObserver::slotChangedObject(const App::DocumentObject&,
|
||||
const App::Property&)
|
||||
{
|
||||
}
|
||||
void DocumentObjectObserver::slotChangedObject(const App::DocumentObject&, const App::Property&)
|
||||
{}
|
||||
|
||||
void DocumentObjectObserver::cancelObservation()
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
/*! Constructor */
|
||||
DocumentT();
|
||||
/*! Constructor */
|
||||
DocumentT(Document*); // explicit bombs
|
||||
DocumentT(Document*); // explicit bombs
|
||||
/*! Constructor */
|
||||
explicit DocumentT(const std::string&);
|
||||
/*! Constructor */
|
||||
@@ -65,18 +65,20 @@ public:
|
||||
/*! Assignment operator */
|
||||
void operator=(const std::string&);
|
||||
|
||||
bool operator==(const DocumentT &other) const {
|
||||
bool operator==(const DocumentT& other) const
|
||||
{
|
||||
return document == other.document;
|
||||
}
|
||||
|
||||
bool operator<(const DocumentT &other) const {
|
||||
bool operator<(const DocumentT& other) const
|
||||
{
|
||||
return document < other.document;
|
||||
}
|
||||
|
||||
/*! Get a pointer to the document or 0 if it doesn't exist any more. */
|
||||
Document* getDocument() const;
|
||||
/*! Get the name of the document. */
|
||||
const std::string &getDocumentName() const;
|
||||
const std::string& getDocumentName() const;
|
||||
/*! Get the document as Python command. */
|
||||
std::string getDocumentPython() const;
|
||||
|
||||
@@ -85,9 +87,9 @@ private:
|
||||
};
|
||||
|
||||
/**
|
||||
* The DocumentObjectT class is a helper class to store the names of a document object and its document.
|
||||
* This can be useful when you cannot rely on that the document or the object still exists when you have to
|
||||
* access it.
|
||||
* The DocumentObjectT class is a helper class to store the names of a document object and its
|
||||
* document. This can be useful when you cannot rely on that the document or the object still exists
|
||||
* when you have to access it.
|
||||
*
|
||||
* @author Werner Mayer
|
||||
*/
|
||||
@@ -97,23 +99,23 @@ public:
|
||||
/*! Constructor */
|
||||
DocumentObjectT();
|
||||
/*! Constructor */
|
||||
DocumentObjectT(const DocumentObjectT &);
|
||||
DocumentObjectT(const DocumentObjectT&);
|
||||
/*! Constructor */
|
||||
DocumentObjectT(DocumentObjectT &&);
|
||||
DocumentObjectT(DocumentObjectT&&);
|
||||
/*! Constructor */
|
||||
explicit DocumentObjectT(const DocumentObject*);
|
||||
/*! Constructor */
|
||||
DocumentObjectT(const Document*, const std::string& objName);
|
||||
/*! Constructor */
|
||||
DocumentObjectT(const char *docName, const char *objName);
|
||||
DocumentObjectT(const char* docName, const char* objName);
|
||||
/*! Constructor */
|
||||
explicit DocumentObjectT(const Property*);
|
||||
/*! Destructor */
|
||||
~DocumentObjectT();
|
||||
/*! Assignment operator */
|
||||
DocumentObjectT &operator=(const DocumentObjectT&);
|
||||
DocumentObjectT& operator=(const DocumentObjectT&);
|
||||
/*! Assignment operator */
|
||||
DocumentObjectT &operator=(DocumentObjectT &&);
|
||||
DocumentObjectT& operator=(DocumentObjectT&&);
|
||||
/*! Assignment operator */
|
||||
void operator=(const DocumentObject*);
|
||||
/*! Assignment operator */
|
||||
@@ -124,7 +126,7 @@ public:
|
||||
/*! Get a pointer to the document or 0 if it doesn't exist any more. */
|
||||
Document* getDocument() const;
|
||||
/*! Get the name of the document. */
|
||||
const std::string &getDocumentName() const;
|
||||
const std::string& getDocumentName() const;
|
||||
/*! Get the document as Python command. */
|
||||
std::string getDocumentPython() const;
|
||||
/*! Get a pointer to the document object or 0 if it doesn't exist any more. */
|
||||
@@ -132,16 +134,17 @@ public:
|
||||
/*! Get a pointer to the property or 0 if it doesn't exist any more. */
|
||||
Property* getProperty() const;
|
||||
/*! Get the name of the document object. */
|
||||
const std::string &getObjectName() const;
|
||||
const std::string& getObjectName() const;
|
||||
/*! Get the label of the document object. */
|
||||
const std::string &getObjectLabel() const;
|
||||
const std::string& getObjectLabel() const;
|
||||
/*! Get the name of the property. */
|
||||
const std::string &getPropertyName() const;
|
||||
const std::string& getPropertyName() const;
|
||||
/*! Get the document object as Python command. */
|
||||
std::string getObjectPython() const;
|
||||
/*! Get the property as Python command. */
|
||||
std::string getPropertyPython() const;
|
||||
/*! Get a pointer to the document or 0 if it doesn't exist any more or the type doesn't match. */
|
||||
/*! Get a pointer to the document or 0 if it doesn't exist any more or the type doesn't match.
|
||||
*/
|
||||
template<typename T>
|
||||
inline T* getObjectAs() const
|
||||
{
|
||||
@@ -160,72 +163,73 @@ private:
|
||||
std::string property;
|
||||
};
|
||||
|
||||
class AppExport SubObjectT : public DocumentObjectT
|
||||
class AppExport SubObjectT: public DocumentObjectT
|
||||
{
|
||||
public:
|
||||
/*! Constructor */
|
||||
SubObjectT();
|
||||
|
||||
/*! Constructor */
|
||||
SubObjectT(const SubObjectT &);
|
||||
SubObjectT(const SubObjectT&);
|
||||
|
||||
/*! Constructor */
|
||||
SubObjectT(SubObjectT &&);
|
||||
SubObjectT(SubObjectT&&);
|
||||
|
||||
/*! Constructor */
|
||||
SubObjectT(const DocumentObjectT & obj, const char *subname);
|
||||
SubObjectT(const DocumentObjectT& obj, const char* subname);
|
||||
|
||||
/*! Constructor */
|
||||
SubObjectT(const DocumentObject*, const char *subname);
|
||||
SubObjectT(const DocumentObject*, const char* subname);
|
||||
|
||||
/*! Constructor */
|
||||
SubObjectT(const DocumentObject*);// explicit bombs
|
||||
SubObjectT(const DocumentObject*); // explicit bombs
|
||||
|
||||
/*! Constructor */
|
||||
SubObjectT(const char *docName, const char *objName, const char *subname);
|
||||
SubObjectT(const char* docName, const char* objName, const char* subname);
|
||||
|
||||
/*! Assignment operator */
|
||||
SubObjectT &operator=(const SubObjectT&);
|
||||
SubObjectT& operator=(const SubObjectT&);
|
||||
|
||||
/*! Assignment operator */
|
||||
SubObjectT &operator=(SubObjectT &&);
|
||||
SubObjectT& operator=(SubObjectT&&);
|
||||
|
||||
/*! Assignment operator */
|
||||
SubObjectT &operator=(const DocumentObjectT&);
|
||||
SubObjectT& operator=(const DocumentObjectT&);
|
||||
|
||||
/*! Assignment operator */
|
||||
SubObjectT &operator=(const App::DocumentObject*);
|
||||
SubObjectT& operator=(const App::DocumentObject*);
|
||||
|
||||
/*! Equality operator */
|
||||
bool operator==(const SubObjectT&) const;
|
||||
|
||||
/// Set the subname path to the sub-object
|
||||
void setSubName(const char *subname);
|
||||
void setSubName(const char* subname);
|
||||
|
||||
/// Set the subname path to the sub-object
|
||||
void setSubName(const std::string &subname) {
|
||||
void setSubName(const std::string& subname)
|
||||
{
|
||||
setSubName(subname.c_str());
|
||||
}
|
||||
|
||||
/// Return the subname path
|
||||
const std::string &getSubName() const;
|
||||
const std::string& getSubName() const;
|
||||
|
||||
/** Return docname#objname (label)
|
||||
* @param docName: optional document name. The document prefix will only be printed
|
||||
* if it is different then the given 'doc'.
|
||||
*/
|
||||
std::string getObjectFullName(const char *docName=nullptr) const;
|
||||
std::string getObjectFullName(const char* docName = nullptr) const;
|
||||
|
||||
/** Return docname#objname.subname (label)
|
||||
* @param doc: optional document name. The document prefix will only be printed
|
||||
* if it is different then the given 'doc'.
|
||||
*/
|
||||
std::string getSubObjectFullName(const char *docName=nullptr) const;
|
||||
std::string getSubObjectFullName(const char* docName = nullptr) const;
|
||||
/// Return the subname path without sub-element
|
||||
std::string getSubNameNoElement() const;
|
||||
|
||||
/// Return the sub-element (Face, Edge, etc) of the subname path
|
||||
const char *getElementName() const;
|
||||
const char* getElementName() const;
|
||||
|
||||
/// Check if there is any sub object reference
|
||||
bool hasSubObject() const;
|
||||
@@ -239,17 +243,17 @@ public:
|
||||
/** Return the old style sub-element name
|
||||
* @param index: if given, then return the element type, and extract the index
|
||||
*/
|
||||
std::string getOldElementName(int *index=nullptr) const;
|
||||
std::string getOldElementName(int* index = nullptr) const;
|
||||
|
||||
/// Return the sub-object
|
||||
DocumentObject *getSubObject() const;
|
||||
DocumentObject* getSubObject() const;
|
||||
|
||||
/// Return all objects along the subname path
|
||||
std::vector<DocumentObject *> getSubObjectList() const;
|
||||
std::vector<DocumentObject*> getSubObjectList() const;
|
||||
|
||||
bool operator<(const SubObjectT &other) const;
|
||||
bool operator<(const SubObjectT& other) const;
|
||||
|
||||
std::string getSubObjectPython(bool force=true) const;
|
||||
std::string getSubObjectPython(bool force = true) const;
|
||||
|
||||
/// Options used by normalize()
|
||||
enum class NormalizeOption : uint8_t
|
||||
@@ -299,16 +303,17 @@ public:
|
||||
PropertyLinkT();
|
||||
|
||||
/*! Constructor */
|
||||
explicit PropertyLinkT(DocumentObject *obj);
|
||||
explicit PropertyLinkT(DocumentObject* obj);
|
||||
|
||||
/*! Constructor */
|
||||
PropertyLinkT(DocumentObject *obj, const std::vector<std::string>& subNames);
|
||||
PropertyLinkT(DocumentObject* obj, const std::vector<std::string>& subNames);
|
||||
|
||||
/*! Constructor */
|
||||
explicit PropertyLinkT(const std::vector<DocumentObject*>& objs);
|
||||
|
||||
/*! Constructor */
|
||||
PropertyLinkT(const std::vector<DocumentObject*>& objs, const std::vector<std::string>& subNames);
|
||||
PropertyLinkT(const std::vector<DocumentObject*>& objs,
|
||||
const std::vector<std::string>& subNames);
|
||||
|
||||
/*! Get the property as Python command. */
|
||||
std::string getPropertyPython() const;
|
||||
@@ -379,7 +384,7 @@ public:
|
||||
* \brief operator =
|
||||
* Assignment operator
|
||||
*/
|
||||
DocumentObjectWeakPtrT& operator= (App::DocumentObject* p);
|
||||
DocumentObjectWeakPtrT& operator=(App::DocumentObject* p);
|
||||
/*!
|
||||
* \brief operator *
|
||||
* \return pointer to the document object
|
||||
@@ -394,12 +399,12 @@ public:
|
||||
* \brief operator ==
|
||||
* \return true if both objects are equal, false otherwise
|
||||
*/
|
||||
bool operator== (const DocumentObjectWeakPtrT& p) const noexcept;
|
||||
bool operator==(const DocumentObjectWeakPtrT& p) const noexcept;
|
||||
/*!
|
||||
* \brief operator !=
|
||||
* \return true if both objects are inequal, false otherwise
|
||||
*/
|
||||
bool operator!= (const DocumentObjectWeakPtrT& p) const noexcept;
|
||||
bool operator!=(const DocumentObjectWeakPtrT& p) const noexcept;
|
||||
/*! Get a pointer to the object or 0 if it doesn't exist any more or the type doesn't match. */
|
||||
template<typename T>
|
||||
inline T* get() const noexcept
|
||||
@@ -423,33 +428,37 @@ private:
|
||||
/**
|
||||
* @brief The WeakPtrT class
|
||||
*/
|
||||
template <class T>
|
||||
template<class T>
|
||||
class WeakPtrT
|
||||
{
|
||||
public:
|
||||
explicit WeakPtrT(T* t) : ptr(t) {
|
||||
}
|
||||
explicit WeakPtrT(T* t)
|
||||
: ptr(t)
|
||||
{}
|
||||
~WeakPtrT() = default;
|
||||
|
||||
/*!
|
||||
* \brief reset
|
||||
* Releases the reference to the managed object. After the call *this manages no object.
|
||||
*/
|
||||
void reset() {
|
||||
void reset()
|
||||
{
|
||||
ptr.reset();
|
||||
}
|
||||
/*!
|
||||
* \brief expired
|
||||
* \return true if the managed object has already been deleted, false otherwise.
|
||||
*/
|
||||
bool expired() const {
|
||||
bool expired() const
|
||||
{
|
||||
return ptr.expired();
|
||||
}
|
||||
/*!
|
||||
* \brief operator =
|
||||
* Assignment operator
|
||||
*/
|
||||
WeakPtrT<T>& operator= (T* p) {
|
||||
WeakPtrT<T>& operator=(T* p)
|
||||
{
|
||||
ptr = p;
|
||||
return *this;
|
||||
}
|
||||
@@ -457,28 +466,32 @@ public:
|
||||
* \brief operator ->
|
||||
* \return pointer to the document object
|
||||
*/
|
||||
T* operator*() const {
|
||||
T* operator*() const
|
||||
{
|
||||
return ptr.get<T>();
|
||||
}
|
||||
/*!
|
||||
* \brief operator ->
|
||||
* \return pointer to the document object
|
||||
*/
|
||||
T* operator->() const {
|
||||
T* operator->() const
|
||||
{
|
||||
return ptr.get<T>();
|
||||
}
|
||||
/*!
|
||||
* \brief operator ==
|
||||
* \return true if both objects are equal, false otherwise
|
||||
*/
|
||||
bool operator== (const WeakPtrT<T>& p) const {
|
||||
bool operator==(const WeakPtrT<T>& p) const
|
||||
{
|
||||
return ptr == p.ptr;
|
||||
}
|
||||
/*!
|
||||
* \brief operator !=
|
||||
* \return true if both objects are inequal, false otherwise
|
||||
*/
|
||||
bool operator!= (const WeakPtrT<T>& p) const {
|
||||
bool operator!=(const WeakPtrT<T>& p) const
|
||||
{
|
||||
return ptr != p.ptr;
|
||||
}
|
||||
/*! Get a pointer to the object or 0 if it doesn't exist any more. */
|
||||
@@ -561,7 +574,7 @@ private:
|
||||
*
|
||||
* @author Werner Mayer
|
||||
*/
|
||||
class AppExport DocumentObjectObserver : public DocumentObserver
|
||||
class AppExport DocumentObjectObserver: public DocumentObserver
|
||||
{
|
||||
|
||||
public:
|
||||
@@ -587,18 +600,18 @@ private:
|
||||
void slotDeletedObject(const App::DocumentObject& Obj) override;
|
||||
/** The property of an observed object has changed */
|
||||
void slotChangedObject(const App::DocumentObject& Obj, const App::Property& Prop) override;
|
||||
/** This method gets called when all observed objects are deleted or the whole document is deleted.
|
||||
* This method can be re-implemented to perform an extra step like closing a dialog that observes
|
||||
* a document.
|
||||
*/
|
||||
/** This method gets called when all observed objects are deleted or the whole document is
|
||||
* deleted. This method can be re-implemented to perform an extra step like closing a dialog
|
||||
* that observes a document.
|
||||
*/
|
||||
virtual void cancelObservation();
|
||||
|
||||
private:
|
||||
std::set<App::DocumentObject*> _objects;
|
||||
};
|
||||
|
||||
} //namespace App
|
||||
} // namespace App
|
||||
|
||||
ENABLE_BITMASK_OPERATORS(App::SubObjectT::NormalizeOption)
|
||||
|
||||
#endif // APP_DOCUMENTOBSERVER_H
|
||||
#endif // APP_DOCUMENTOBSERVER_H
|
||||
|
||||
@@ -46,9 +46,10 @@ void DocumentObserverPython::addObserver(const Py::Object& obj)
|
||||
|
||||
void DocumentObserverPython::removeObserver(const Py::Object& obj)
|
||||
{
|
||||
DocumentObserverPython* obs=nullptr;
|
||||
for (std::vector<DocumentObserverPython*>::iterator it =
|
||||
_instances.begin(); it != _instances.end(); ++it) {
|
||||
DocumentObserverPython* obs = nullptr;
|
||||
for (std::vector<DocumentObserverPython*>::iterator it = _instances.begin();
|
||||
it != _instances.end();
|
||||
++it) {
|
||||
if ((*it)->inst == obj) {
|
||||
obs = *it;
|
||||
_instances.erase(it);
|
||||
@@ -59,33 +60,34 @@ void DocumentObserverPython::removeObserver(const Py::Object& obj)
|
||||
delete obs;
|
||||
}
|
||||
|
||||
DocumentObserverPython::DocumentObserverPython(const Py::Object& obj) : inst(obj)
|
||||
DocumentObserverPython::DocumentObserverPython(const Py::Object& obj)
|
||||
: inst(obj)
|
||||
{
|
||||
#define FC_PY_ELEMENT_ARG0(_name1, _name2) do {\
|
||||
FC_PY_GetCallable(obj.ptr(), "slot" #_name1, py##_name1.py);\
|
||||
if (!py##_name1.py.isNone())\
|
||||
py##_name1.slot = App::GetApplication().signal##_name2.connect(\
|
||||
std::bind(&DocumentObserverPython::slot##_name1, this));\
|
||||
}\
|
||||
while(0);
|
||||
#define FC_PY_ELEMENT_ARG0(_name1, _name2) \
|
||||
do { \
|
||||
FC_PY_GetCallable(obj.ptr(), "slot" #_name1, py##_name1.py); \
|
||||
if (!py##_name1.py.isNone()) \
|
||||
py##_name1.slot = App::GetApplication().signal##_name2.connect( \
|
||||
std::bind(&DocumentObserverPython::slot##_name1, this)); \
|
||||
} while (0);
|
||||
|
||||
|
||||
#define FC_PY_ELEMENT_ARG1(_name1, _name2) do {\
|
||||
FC_PY_GetCallable(obj.ptr(), "slot" #_name1, py##_name1.py);\
|
||||
if (!py##_name1.py.isNone())\
|
||||
py##_name1.slot = App::GetApplication().signal##_name2.connect(\
|
||||
std::bind(&DocumentObserverPython::slot##_name1, this, sp::_1));\
|
||||
}\
|
||||
while(0);
|
||||
#define FC_PY_ELEMENT_ARG1(_name1, _name2) \
|
||||
do { \
|
||||
FC_PY_GetCallable(obj.ptr(), "slot" #_name1, py##_name1.py); \
|
||||
if (!py##_name1.py.isNone()) \
|
||||
py##_name1.slot = App::GetApplication().signal##_name2.connect( \
|
||||
std::bind(&DocumentObserverPython::slot##_name1, this, sp::_1)); \
|
||||
} while (0);
|
||||
|
||||
//NOLINTBEGIN
|
||||
#define FC_PY_ELEMENT_ARG2(_name1, _name2) do {\
|
||||
FC_PY_GetCallable(obj.ptr(), "slot" #_name1, py##_name1.py);\
|
||||
if (!py##_name1.py.isNone())\
|
||||
py##_name1.slot = App::GetApplication().signal##_name2.connect(\
|
||||
std::bind(&DocumentObserverPython::slot##_name1, this, sp::_1, sp::_2));\
|
||||
}\
|
||||
while(0);
|
||||
// NOLINTBEGIN
|
||||
#define FC_PY_ELEMENT_ARG2(_name1, _name2) \
|
||||
do { \
|
||||
FC_PY_GetCallable(obj.ptr(), "slot" #_name1, py##_name1.py); \
|
||||
if (!py##_name1.py.isNone()) \
|
||||
py##_name1.slot = App::GetApplication().signal##_name2.connect( \
|
||||
std::bind(&DocumentObserverPython::slot##_name1, this, sp::_1, sp::_2)); \
|
||||
} while (0);
|
||||
|
||||
FC_PY_ELEMENT_ARG1(CreatedDocument, NewDocument)
|
||||
FC_PY_ELEMENT_ARG1(DeletedDocument, DeleteDocument)
|
||||
@@ -116,7 +118,7 @@ DocumentObserverPython::DocumentObserverPython(const Py::Object& obj) : inst(obj
|
||||
FC_PY_ELEMENT_ARG2(ChangePropertyEditor, ChangePropertyEditor)
|
||||
FC_PY_ELEMENT_ARG2(BeforeAddingDynamicExtension, BeforeAddingDynamicExtension)
|
||||
FC_PY_ELEMENT_ARG2(AddedDynamicExtension, AddedDynamicExtension)
|
||||
//NOLINTEND
|
||||
// NOLINTEND
|
||||
}
|
||||
|
||||
DocumentObserverPython::~DocumentObserverPython() = default;
|
||||
@@ -127,10 +129,10 @@ void DocumentObserverPython::slotCreatedDocument(const App::Document& Doc)
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
|
||||
Base::pyCall(pyCreatedDocument.ptr(),args.ptr());
|
||||
Base::pyCall(pyCreatedDocument.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -141,10 +143,10 @@ void DocumentObserverPython::slotDeletedDocument(const App::Document& Doc)
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
|
||||
Base::pyCall(pyDeletedDocument.ptr(),args.ptr());
|
||||
Base::pyCall(pyDeletedDocument.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -155,10 +157,10 @@ void DocumentObserverPython::slotRelabelDocument(const App::Document& Doc)
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
|
||||
Base::pyCall(pyRelabelDocument.ptr(),args.ptr());
|
||||
Base::pyCall(pyRelabelDocument.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -169,10 +171,10 @@ void DocumentObserverPython::slotActivateDocument(const App::Document& Doc)
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
|
||||
Base::pyCall(pyActivateDocument.ptr(),args.ptr());
|
||||
Base::pyCall(pyActivateDocument.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -183,10 +185,10 @@ void DocumentObserverPython::slotUndoDocument(const App::Document& Doc)
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
|
||||
Base::pyCall(pyUndoDocument.ptr(),args.ptr());
|
||||
Base::pyCall(pyUndoDocument.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -198,10 +200,10 @@ void DocumentObserverPython::slotRedoDocument(const App::Document& Doc)
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
|
||||
Base::pyCall(pyRedoDocument.ptr(),args.ptr());
|
||||
Base::pyCall(pyRedoDocument.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -213,7 +215,7 @@ void DocumentObserverPython::slotUndo()
|
||||
Base::pyCall(pyUndo.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -225,7 +227,7 @@ void DocumentObserverPython::slotRedo()
|
||||
Base::pyCall(pyRedo.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -236,10 +238,10 @@ void DocumentObserverPython::slotBeforeCloseTransaction(bool abort)
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::Boolean(abort));
|
||||
Base::pyCall(pyBeforeCloseTransaction.ptr(),args.ptr());
|
||||
Base::pyCall(pyBeforeCloseTransaction.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -250,15 +252,16 @@ void DocumentObserverPython::slotCloseTransaction(bool abort)
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::Boolean(abort));
|
||||
Base::pyCall(pyCloseTransaction.ptr(),args.ptr());
|
||||
Base::pyCall(pyCloseTransaction.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentObserverPython::slotBeforeChangeDocument(const App::Document& Doc, const App::Property& Prop)
|
||||
void DocumentObserverPython::slotBeforeChangeDocument(const App::Document& Doc,
|
||||
const App::Property& Prop)
|
||||
{
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
@@ -269,16 +272,17 @@ void DocumentObserverPython::slotBeforeChangeDocument(const App::Document& Doc,
|
||||
const char* prop_name = Doc.getPropertyName(&Prop);
|
||||
if (prop_name) {
|
||||
args.setItem(1, Py::String(prop_name));
|
||||
Base::pyCall(pyBeforeChangeDocument.ptr(),args.ptr());
|
||||
Base::pyCall(pyBeforeChangeDocument.ptr(), args.ptr());
|
||||
}
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentObserverPython::slotChangedDocument(const App::Document& Doc, const App::Property& Prop)
|
||||
void DocumentObserverPython::slotChangedDocument(const App::Document& Doc,
|
||||
const App::Property& Prop)
|
||||
{
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
@@ -289,11 +293,11 @@ void DocumentObserverPython::slotChangedDocument(const App::Document& Doc, const
|
||||
const char* prop_name = Doc.getPropertyName(&Prop);
|
||||
if (prop_name) {
|
||||
args.setItem(1, Py::String(prop_name));
|
||||
Base::pyCall(pyChangedDocument.ptr(),args.ptr());
|
||||
Base::pyCall(pyChangedDocument.ptr(), args.ptr());
|
||||
}
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -304,10 +308,10 @@ void DocumentObserverPython::slotCreatedObject(const App::DocumentObject& Obj)
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::asObject(const_cast<App::DocumentObject&>(Obj).getPyObject()));
|
||||
Base::pyCall(pyCreatedObject.ptr(),args.ptr());
|
||||
Base::pyCall(pyCreatedObject.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -318,16 +322,16 @@ void DocumentObserverPython::slotDeletedObject(const App::DocumentObject& Obj)
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::asObject(const_cast<App::DocumentObject&>(Obj).getPyObject()));
|
||||
Base::pyCall(pyDeletedObject.ptr(),args.ptr());
|
||||
Base::pyCall(pyDeletedObject.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentObserverPython::slotBeforeChangeObject(const App::DocumentObject& Obj,
|
||||
const App::Property& Prop)
|
||||
const App::Property& Prop)
|
||||
{
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
@@ -338,11 +342,11 @@ void DocumentObserverPython::slotBeforeChangeObject(const App::DocumentObject& O
|
||||
const char* prop_name = Obj.getPropertyName(&Prop);
|
||||
if (prop_name) {
|
||||
args.setItem(1, Py::String(prop_name));
|
||||
Base::pyCall(pyBeforeChangeObject.ptr(),args.ptr());
|
||||
Base::pyCall(pyBeforeChangeObject.ptr(), args.ptr());
|
||||
}
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -359,11 +363,11 @@ void DocumentObserverPython::slotChangedObject(const App::DocumentObject& Obj,
|
||||
const char* prop_name = Obj.getPropertyName(&Prop);
|
||||
if (prop_name) {
|
||||
args.setItem(1, Py::String(prop_name));
|
||||
Base::pyCall(pyChangedObject.ptr(),args.ptr());
|
||||
Base::pyCall(pyChangedObject.ptr(), args.ptr());
|
||||
}
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -374,10 +378,10 @@ void DocumentObserverPython::slotRecomputedObject(const App::DocumentObject& Obj
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::asObject(const_cast<App::DocumentObject&>(Obj).getPyObject()));
|
||||
Base::pyCall(pyRecomputedObject.ptr(),args.ptr());
|
||||
Base::pyCall(pyRecomputedObject.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -388,10 +392,10 @@ void DocumentObserverPython::slotRecomputedDocument(const App::Document& doc)
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
|
||||
Base::pyCall(pyRecomputedDocument.ptr(),args.ptr());
|
||||
Base::pyCall(pyRecomputedDocument.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -402,10 +406,10 @@ void DocumentObserverPython::slotBeforeRecomputeDocument(const App::Document& do
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
|
||||
Base::pyCall(pyBeforeRecomputeDocument.ptr(),args.ptr());
|
||||
Base::pyCall(pyBeforeRecomputeDocument.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -417,10 +421,10 @@ void DocumentObserverPython::slotOpenTransaction(const App::Document& doc, std::
|
||||
Py::Tuple args(2);
|
||||
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
|
||||
args.setItem(1, Py::String(str));
|
||||
Base::pyCall(pyOpenTransaction.ptr(),args.ptr());
|
||||
Base::pyCall(pyOpenTransaction.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -431,10 +435,10 @@ void DocumentObserverPython::slotCommitTransaction(const App::Document& doc)
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
|
||||
Base::pyCall(pyCommitTransaction.ptr(),args.ptr());
|
||||
Base::pyCall(pyCommitTransaction.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -445,10 +449,10 @@ void DocumentObserverPython::slotAbortTransaction(const App::Document& doc)
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
|
||||
Base::pyCall(pyAbortTransaction.ptr(),args.ptr());
|
||||
Base::pyCall(pyAbortTransaction.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -465,11 +469,11 @@ void DocumentObserverPython::slotAppendDynamicProperty(const App::Property& Prop
|
||||
const char* prop_name = container->getPropertyName(&Prop);
|
||||
if (prop_name) {
|
||||
args.setItem(1, Py::String(prop_name));
|
||||
Base::pyCall(pyAppendDynamicProperty.ptr(),args.ptr());
|
||||
Base::pyCall(pyAppendDynamicProperty.ptr(), args.ptr());
|
||||
}
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -486,16 +490,17 @@ void DocumentObserverPython::slotRemoveDynamicProperty(const App::Property& Prop
|
||||
const char* prop_name = container->getPropertyName(&Prop);
|
||||
if (prop_name) {
|
||||
args.setItem(1, Py::String(prop_name));
|
||||
Base::pyCall(pyRemoveDynamicProperty.ptr(),args.ptr());
|
||||
Base::pyCall(pyRemoveDynamicProperty.ptr(), args.ptr());
|
||||
}
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentObserverPython::slotChangePropertyEditor(const App::Document &, const App::Property& Prop)
|
||||
void DocumentObserverPython::slotChangePropertyEditor(const App::Document&,
|
||||
const App::Property& Prop)
|
||||
{
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
@@ -507,72 +512,76 @@ void DocumentObserverPython::slotChangePropertyEditor(const App::Document &, con
|
||||
const char* prop_name = container->getPropertyName(&Prop);
|
||||
if (prop_name) {
|
||||
args.setItem(1, Py::String(prop_name));
|
||||
Base::pyCall(pyChangePropertyEditor.ptr(),args.ptr());
|
||||
Base::pyCall(pyChangePropertyEditor.ptr(), args.ptr());
|
||||
}
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentObserverPython::slotStartSaveDocument(const App::Document& doc, const std::string& file)
|
||||
void DocumentObserverPython::slotStartSaveDocument(const App::Document& doc,
|
||||
const std::string& file)
|
||||
{
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::Tuple args(2);
|
||||
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
|
||||
args.setItem(1, Py::String(file));
|
||||
Base::pyCall(pyStartSaveDocument.ptr(),args.ptr());
|
||||
Base::pyCall(pyStartSaveDocument.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentObserverPython::slotFinishSaveDocument(const App::Document& doc, const std::string& file)
|
||||
void DocumentObserverPython::slotFinishSaveDocument(const App::Document& doc,
|
||||
const std::string& file)
|
||||
{
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::Tuple args(2);
|
||||
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
|
||||
args.setItem(1, Py::String(file));
|
||||
Base::pyCall(pyFinishSaveDocument.ptr(),args.ptr());
|
||||
Base::pyCall(pyFinishSaveDocument.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentObserverPython::slotBeforeAddingDynamicExtension(const App::ExtensionContainer& extcont, std::string extension)
|
||||
void DocumentObserverPython::slotBeforeAddingDynamicExtension(
|
||||
const App::ExtensionContainer& extcont,
|
||||
std::string extension)
|
||||
{
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::Tuple args(2);
|
||||
args.setItem(0, Py::asObject(const_cast<App::ExtensionContainer&>(extcont).getPyObject()));
|
||||
args.setItem(1, Py::String(extension));
|
||||
Base::pyCall(pyBeforeAddingDynamicExtension.ptr(),args.ptr());
|
||||
Base::pyCall(pyBeforeAddingDynamicExtension.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentObserverPython::slotAddedDynamicExtension(const App::ExtensionContainer& extcont, std::string extension)
|
||||
void DocumentObserverPython::slotAddedDynamicExtension(const App::ExtensionContainer& extcont,
|
||||
std::string extension)
|
||||
{
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::Tuple args(2);
|
||||
args.setItem(0, Py::asObject(const_cast<App::ExtensionContainer&>(extcont).getPyObject()));
|
||||
args.setItem(1, Py::String(extension));
|
||||
Base::pyCall(pyAddedDynamicExtension.ptr(),args.ptr());
|
||||
Base::pyCall(pyAddedDynamicExtension.ptr(), args.ptr());
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ private:
|
||||
/** Called when an object gets a dynamic property removed*/
|
||||
void slotRemoveDynamicProperty(const App::Property& Prop);
|
||||
/** Called when an object property gets a new editor relevant status like hidden or read only*/
|
||||
void slotChangePropertyEditor(const App::Document &Doc, const App::Property& Prop);
|
||||
void slotChangePropertyEditor(const App::Document& Doc, const App::Property& Prop);
|
||||
/** Called when a document is about to be saved*/
|
||||
void slotStartSaveDocument(const App::Document&, const std::string&);
|
||||
/** Called when an document has been saved*/
|
||||
@@ -121,12 +121,14 @@ private:
|
||||
Py::Object inst;
|
||||
static std::vector<DocumentObserverPython*> _instances;
|
||||
|
||||
using Connection = struct PythonObject {
|
||||
boost::signals2::scoped_connection slot;
|
||||
Py::Object py;
|
||||
PyObject* ptr() {
|
||||
return py.ptr();
|
||||
}
|
||||
using Connection = struct PythonObject
|
||||
{
|
||||
boost::signals2::scoped_connection slot;
|
||||
Py::Object py;
|
||||
PyObject* ptr()
|
||||
{
|
||||
return py.ptr();
|
||||
}
|
||||
};
|
||||
|
||||
Connection pyCreatedDocument;
|
||||
@@ -160,6 +162,6 @@ private:
|
||||
Connection pyAddedDynamicExtension;
|
||||
};
|
||||
|
||||
} //namespace App
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_DOCUMENTOBSERVERPYTHON_H
|
||||
#endif // APP_DOCUMENTOBSERVERPYTHON_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,7 +33,7 @@
|
||||
#include "PropertyContainer.h"
|
||||
|
||||
|
||||
FC_LOG_LEVEL_INIT("Property",true,true)
|
||||
FC_LOG_LEVEL_INIT("Property", true, true)
|
||||
|
||||
|
||||
using namespace App;
|
||||
@@ -46,65 +46,75 @@ DynamicProperty::~DynamicProperty()
|
||||
clear();
|
||||
}
|
||||
|
||||
void DynamicProperty::clear() {
|
||||
auto &index = props.get<0>();
|
||||
for(auto &v : index)
|
||||
void DynamicProperty::clear()
|
||||
{
|
||||
auto& index = props.get<0>();
|
||||
for (auto& v : index) {
|
||||
delete v.property;
|
||||
}
|
||||
index.clear();
|
||||
}
|
||||
|
||||
void DynamicProperty::getPropertyList(std::vector<Property*> &List) const
|
||||
void DynamicProperty::getPropertyList(std::vector<Property*>& List) const
|
||||
{
|
||||
for (auto &v : props.get<0>())
|
||||
for (auto& v : props.get<0>()) {
|
||||
List.push_back(v.property);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicProperty::getPropertyNamedList(std::vector<std::pair<const char*, Property*> > &List) const
|
||||
void DynamicProperty::getPropertyNamedList(
|
||||
std::vector<std::pair<const char*, Property*>>& List) const
|
||||
{
|
||||
for (auto &v : props.get<0>())
|
||||
List.emplace_back(v.getName(),v.property);
|
||||
for (auto& v : props.get<0>()) {
|
||||
List.emplace_back(v.getName(), v.property);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicProperty::getPropertyMap(std::map<std::string,Property*> &Map) const
|
||||
void DynamicProperty::getPropertyMap(std::map<std::string, Property*>& Map) const
|
||||
{
|
||||
for (auto &v : props.get<0>())
|
||||
for (auto& v : props.get<0>()) {
|
||||
Map[v.name] = v.property;
|
||||
}
|
||||
}
|
||||
|
||||
Property *DynamicProperty::getDynamicPropertyByName(const char* name) const
|
||||
Property* DynamicProperty::getDynamicPropertyByName(const char* name) const
|
||||
{
|
||||
auto &index = props.get<0>();
|
||||
auto& index = props.get<0>();
|
||||
auto it = index.find(name);
|
||||
if (it != index.end())
|
||||
if (it != index.end()) {
|
||||
return it->property;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> DynamicProperty::getDynamicPropertyNames() const
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
auto &index = props.get<0>();
|
||||
auto& index = props.get<0>();
|
||||
names.reserve(index.size());
|
||||
for(auto &v : index)
|
||||
for (auto& v : index) {
|
||||
names.push_back(v.name);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
short DynamicProperty::getPropertyType(const Property* prop) const
|
||||
{
|
||||
return prop?prop->getType():0;
|
||||
return prop ? prop->getType() : 0;
|
||||
}
|
||||
|
||||
short DynamicProperty::getPropertyType(const char *name) const
|
||||
short DynamicProperty::getPropertyType(const char* name) const
|
||||
{
|
||||
auto &index = props.get<0>();
|
||||
auto& index = props.get<0>();
|
||||
auto it = index.find(name);
|
||||
if (it != index.end()) {
|
||||
short attr = it->attr;
|
||||
if (it->hidden)
|
||||
if (it->hidden) {
|
||||
attr |= Prop_Hidden;
|
||||
if (it->readonly)
|
||||
}
|
||||
if (it->readonly) {
|
||||
attr |= Prop_ReadOnly;
|
||||
}
|
||||
return attr;
|
||||
}
|
||||
return 0;
|
||||
@@ -112,92 +122,113 @@ short DynamicProperty::getPropertyType(const char *name) const
|
||||
|
||||
const char* DynamicProperty::getPropertyGroup(const Property* prop) const
|
||||
{
|
||||
auto &index = props.get<1>();
|
||||
auto& index = props.get<1>();
|
||||
auto it = index.find(const_cast<Property*>(prop));
|
||||
if(it!=index.end())
|
||||
if (it != index.end()) {
|
||||
return it->group.c_str();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* DynamicProperty::getPropertyGroup(const char *name) const
|
||||
const char* DynamicProperty::getPropertyGroup(const char* name) const
|
||||
{
|
||||
auto &index = props.get<0>();
|
||||
auto& index = props.get<0>();
|
||||
auto it = index.find(name);
|
||||
if (it != index.end())
|
||||
if (it != index.end()) {
|
||||
return it->group.c_str();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* DynamicProperty::getPropertyDocumentation(const Property* prop) const
|
||||
{
|
||||
auto &index = props.get<1>();
|
||||
auto& index = props.get<1>();
|
||||
auto it = index.find(const_cast<Property*>(prop));
|
||||
if(it!=index.end())
|
||||
if (it != index.end()) {
|
||||
return it->doc.c_str();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* DynamicProperty::getPropertyDocumentation(const char *name) const
|
||||
const char* DynamicProperty::getPropertyDocumentation(const char* name) const
|
||||
{
|
||||
auto &index = props.get<0>();
|
||||
auto& index = props.get<0>();
|
||||
auto it = index.find(name);
|
||||
if (it != index.end())
|
||||
if (it != index.end()) {
|
||||
return it->doc.c_str();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Property* DynamicProperty::addDynamicProperty(PropertyContainer &pc, const char* type,
|
||||
const char* name, const char* group, const char* doc, short attr, bool ro, bool hidden)
|
||||
Property* DynamicProperty::addDynamicProperty(PropertyContainer& pc,
|
||||
const char* type,
|
||||
const char* name,
|
||||
const char* group,
|
||||
const char* doc,
|
||||
short attr,
|
||||
bool ro,
|
||||
bool hidden)
|
||||
{
|
||||
if(!type)
|
||||
if (!type) {
|
||||
type = "<null>";
|
||||
}
|
||||
|
||||
std::string _name;
|
||||
|
||||
static ParameterGrp::handle hGrp = GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Document");
|
||||
if(hGrp->GetBool("AutoNameDynamicProperty",false)) {
|
||||
if(!name || !name[0])
|
||||
static ParameterGrp::handle hGrp =
|
||||
GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document");
|
||||
if (hGrp->GetBool("AutoNameDynamicProperty", false)) {
|
||||
if (!name || !name[0]) {
|
||||
name = type;
|
||||
_name = getUniquePropertyName(pc,name);
|
||||
if(_name != name) {
|
||||
FC_WARN(pc.getFullName() << " rename dynamic property from '"
|
||||
<< name << "' to '" << _name << "'");
|
||||
}
|
||||
_name = getUniquePropertyName(pc, name);
|
||||
if (_name != name) {
|
||||
FC_WARN(pc.getFullName()
|
||||
<< " rename dynamic property from '" << name << "' to '" << _name << "'");
|
||||
}
|
||||
name = _name.c_str();
|
||||
} else if(!name)
|
||||
name = "<null>"; // setting a bad name to trigger exception
|
||||
}
|
||||
else if (!name) {
|
||||
name = "<null>"; // setting a bad name to trigger exception
|
||||
}
|
||||
|
||||
auto prop = pc.getPropertyByName(name);
|
||||
if(prop && prop->getContainer()==&pc)
|
||||
FC_THROWM(Base::NameError, "Property " << pc.getFullName() << '.' << name << " already exists");
|
||||
if (prop && prop->getContainer() == &pc) {
|
||||
FC_THROWM(Base::NameError,
|
||||
"Property " << pc.getFullName() << '.' << name << " already exists");
|
||||
}
|
||||
|
||||
if(Base::Tools::getIdentifier(name) != name)
|
||||
if (Base::Tools::getIdentifier(name) != name) {
|
||||
FC_THROWM(Base::NameError, "Invalid property name '" << name << "'");
|
||||
}
|
||||
|
||||
Base::Type propType = Base::Type::getTypeIfDerivedFrom(type, App::Property::getClassTypeId(), true);
|
||||
Base::Type propType =
|
||||
Base::Type::getTypeIfDerivedFrom(type, App::Property::getClassTypeId(), true);
|
||||
if (propType.isBad()) {
|
||||
FC_THROWM(Base::TypeError, "Invalid type "
|
||||
<< type << " for property " << pc.getFullName() << '.' << name);
|
||||
FC_THROWM(Base::TypeError,
|
||||
"Invalid type " << type << " for property " << pc.getFullName() << '.' << name);
|
||||
}
|
||||
|
||||
void* propInstance = propType.createInstance();
|
||||
if (!propInstance) {
|
||||
FC_THROWM(Base::RuntimeError, "Failed to create property "
|
||||
<< pc.getFullName() << '.' << name << " of type " << type);
|
||||
FC_THROWM(Base::RuntimeError,
|
||||
"Failed to create property " << pc.getFullName() << '.' << name << " of type "
|
||||
<< type);
|
||||
}
|
||||
|
||||
Property* pcProperty = static_cast<Property*>(propInstance);
|
||||
|
||||
auto res = props.get<0>().emplace(pcProperty,name, nullptr, group, doc, attr, ro, hidden);
|
||||
auto res = props.get<0>().emplace(pcProperty, name, nullptr, group, doc, attr, ro, hidden);
|
||||
|
||||
pcProperty->setContainer(&pc);
|
||||
pcProperty->myName = res.first->name.c_str();
|
||||
|
||||
if(ro)
|
||||
if (ro) {
|
||||
attr |= Prop_ReadOnly;
|
||||
if(hidden)
|
||||
}
|
||||
if (hidden) {
|
||||
attr |= Prop_Hidden;
|
||||
}
|
||||
|
||||
pcProperty->syncType(attr);
|
||||
pcProperty->StatusBits.set((size_t)Property::PropDynamic);
|
||||
@@ -207,21 +238,29 @@ Property* DynamicProperty::addDynamicProperty(PropertyContainer &pc, const char*
|
||||
return pcProperty;
|
||||
}
|
||||
|
||||
bool DynamicProperty::addProperty(Property *prop)
|
||||
bool DynamicProperty::addProperty(Property* prop)
|
||||
{
|
||||
if(!prop || !prop->hasName())
|
||||
if (!prop || !prop->hasName()) {
|
||||
return false;
|
||||
auto &index = props.get<0>();
|
||||
if(index.count(prop->getName()))
|
||||
}
|
||||
auto& index = props.get<0>();
|
||||
if (index.count(prop->getName())) {
|
||||
return false;
|
||||
index.emplace(prop,std::string(),prop->getName(),
|
||||
prop->getGroup(),prop->getDocumentation(),prop->getType(),false,false);
|
||||
}
|
||||
index.emplace(prop,
|
||||
std::string(),
|
||||
prop->getName(),
|
||||
prop->getGroup(),
|
||||
prop->getDocumentation(),
|
||||
prop->getType(),
|
||||
false,
|
||||
false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DynamicProperty::removeProperty(const Property *prop)
|
||||
bool DynamicProperty::removeProperty(const Property* prop)
|
||||
{
|
||||
auto &index = props.get<1>();
|
||||
auto& index = props.get<1>();
|
||||
auto it = index.find(const_cast<Property*>(prop));
|
||||
if (it != index.end()) {
|
||||
index.erase(it);
|
||||
@@ -232,14 +271,16 @@ bool DynamicProperty::removeProperty(const Property *prop)
|
||||
|
||||
bool DynamicProperty::removeDynamicProperty(const char* name)
|
||||
{
|
||||
auto &index = props.get<0>();
|
||||
auto& index = props.get<0>();
|
||||
auto it = index.find(name);
|
||||
if (it != index.end()) {
|
||||
if(it->property->testStatus(Property::LockDynamic))
|
||||
if (it->property->testStatus(Property::LockDynamic)) {
|
||||
throw Base::RuntimeError("property is locked");
|
||||
else if(!it->property->testStatus(Property::PropDynamic))
|
||||
}
|
||||
else if (!it->property->testStatus(Property::PropDynamic)) {
|
||||
throw Base::RuntimeError("property is not dynamic");
|
||||
Property *prop = it->property;
|
||||
}
|
||||
Property* prop = it->property;
|
||||
GetApplication().signalRemoveDynamicProperty(*prop);
|
||||
|
||||
// Handle possible recursive calls of removeDynamicProperty
|
||||
@@ -255,12 +296,12 @@ bool DynamicProperty::removeDynamicProperty(const char* name)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string DynamicProperty::getUniquePropertyName(PropertyContainer &pc, const char *Name) const
|
||||
std::string DynamicProperty::getUniquePropertyName(PropertyContainer& pc, const char* Name) const
|
||||
{
|
||||
std::string CleanName = Base::Tools::getIdentifier(Name);
|
||||
|
||||
// name in use?
|
||||
std::map<std::string,Property*> objectProps;
|
||||
std::map<std::string, Property*> objectProps;
|
||||
pc.getPropertyMap(objectProps);
|
||||
auto pos = objectProps.find(CleanName);
|
||||
|
||||
@@ -271,38 +312,42 @@ std::string DynamicProperty::getUniquePropertyName(PropertyContainer &pc, const
|
||||
else {
|
||||
std::vector<std::string> names;
|
||||
names.reserve(objectProps.size());
|
||||
for (pos = objectProps.begin();pos != objectProps.end();++pos) {
|
||||
for (pos = objectProps.begin(); pos != objectProps.end(); ++pos) {
|
||||
names.push_back(pos->first);
|
||||
}
|
||||
return Base::Tools::getUniqueName(CleanName, names);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicProperty::save(const Property *prop, Base::Writer &writer) const
|
||||
void DynamicProperty::save(const Property* prop, Base::Writer& writer) const
|
||||
{
|
||||
auto &index = props.get<1>();
|
||||
auto& index = props.get<1>();
|
||||
auto it = index.find(const_cast<Property*>(prop));
|
||||
if(it != index.end()) {
|
||||
auto &data = *it;
|
||||
if (it != index.end()) {
|
||||
auto& data = *it;
|
||||
writer.Stream() << "\" group=\"" << Base::Persistence::encodeAttribute(data.group)
|
||||
<< "\" doc=\"" << Base::Persistence::encodeAttribute(data.doc)
|
||||
<< "\" attr=\"" << data.attr << "\" ro=\"" << data.readonly
|
||||
<< "\" hide=\"" << data.hidden;
|
||||
<< "\" attr=\"" << data.attr << "\" ro=\"" << data.readonly << "\" hide=\""
|
||||
<< data.hidden;
|
||||
}
|
||||
}
|
||||
|
||||
Property *DynamicProperty::restore(PropertyContainer &pc,
|
||||
const char *PropName, const char *TypeName, Base::XMLReader &reader)
|
||||
Property* DynamicProperty::restore(PropertyContainer& pc,
|
||||
const char* PropName,
|
||||
const char* TypeName,
|
||||
Base::XMLReader& reader)
|
||||
{
|
||||
if (!reader.hasAttribute("group"))
|
||||
if (!reader.hasAttribute("group")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
short attribute = 0;
|
||||
bool readonly = false, hidden = false;
|
||||
const char *group=nullptr, *doc=nullptr, *attr=nullptr, *ro=nullptr, *hide=nullptr;
|
||||
const char *group = nullptr, *doc = nullptr, *attr = nullptr, *ro = nullptr, *hide = nullptr;
|
||||
group = reader.getAttribute("group");
|
||||
if (reader.hasAttribute("doc"))
|
||||
if (reader.hasAttribute("doc")) {
|
||||
doc = reader.getAttribute("doc");
|
||||
}
|
||||
if (reader.hasAttribute("attr")) {
|
||||
attr = reader.getAttribute("attr");
|
||||
if (attr) {
|
||||
@@ -312,42 +357,54 @@ Property *DynamicProperty::restore(PropertyContainer &pc,
|
||||
}
|
||||
if (reader.hasAttribute("ro")) {
|
||||
ro = reader.getAttribute("ro");
|
||||
if (ro) readonly = (ro[0]-48) != 0;
|
||||
if (ro) {
|
||||
readonly = (ro[0] - 48) != 0;
|
||||
}
|
||||
}
|
||||
if (reader.hasAttribute("hide")) {
|
||||
hide = reader.getAttribute("hide");
|
||||
if (hide) hidden = (hide[0]-48) != 0;
|
||||
if (hide) {
|
||||
hidden = (hide[0] - 48) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
return addDynamicProperty(pc,TypeName, PropName, group, doc, attribute, readonly, hidden);
|
||||
return addDynamicProperty(pc, TypeName, PropName, group, doc, attribute, readonly, hidden);
|
||||
}
|
||||
|
||||
DynamicProperty::PropData DynamicProperty::getDynamicPropertyData(const Property *prop) const
|
||||
DynamicProperty::PropData DynamicProperty::getDynamicPropertyData(const Property* prop) const
|
||||
{
|
||||
auto &index = props.get<1>();
|
||||
auto& index = props.get<1>();
|
||||
auto it = index.find(const_cast<Property*>(prop));
|
||||
if(it != index.end())
|
||||
if (it != index.end()) {
|
||||
return *it;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool DynamicProperty::changeDynamicProperty(const Property *prop, const char *group, const char *doc) {
|
||||
auto &index = props.get<1>();
|
||||
bool DynamicProperty::changeDynamicProperty(const Property* prop,
|
||||
const char* group,
|
||||
const char* doc)
|
||||
{
|
||||
auto& index = props.get<1>();
|
||||
auto it = index.find(const_cast<Property*>(prop));
|
||||
if (it == index.end())
|
||||
if (it == index.end()) {
|
||||
return false;
|
||||
if(group)
|
||||
}
|
||||
if (group) {
|
||||
it->group = group;
|
||||
if(doc)
|
||||
}
|
||||
if (doc) {
|
||||
it->doc = doc;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *DynamicProperty::getPropertyName(const Property *prop) const
|
||||
const char* DynamicProperty::getPropertyName(const Property* prop) const
|
||||
{
|
||||
auto &index = props.get<1>();
|
||||
auto& index = props.get<1>();
|
||||
auto it = index.find(const_cast<Property*>(prop));
|
||||
if(it != index.end())
|
||||
if (it != index.end()) {
|
||||
return it->getName();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -35,11 +35,12 @@
|
||||
#include <boost/multi_index/mem_fun.hpp>
|
||||
|
||||
|
||||
namespace Base {
|
||||
namespace Base
|
||||
{
|
||||
class Writer;
|
||||
class XMLReader;
|
||||
class XMLWriter;
|
||||
}
|
||||
} // namespace Base
|
||||
|
||||
namespace App
|
||||
{
|
||||
@@ -48,15 +49,24 @@ class PropertyContainer;
|
||||
|
||||
namespace bmi = boost::multi_index;
|
||||
|
||||
struct CStringHasher {
|
||||
inline std::size_t operator()(const char *s) const {
|
||||
if(!s) return 0;
|
||||
return boost::hash_range(s,s+std::strlen(s));
|
||||
struct CStringHasher
|
||||
{
|
||||
inline std::size_t operator()(const char* s) const
|
||||
{
|
||||
if (!s) {
|
||||
return 0;
|
||||
}
|
||||
return boost::hash_range(s, s + std::strlen(s));
|
||||
}
|
||||
inline bool operator()(const char *a, const char *b) const {
|
||||
if(!a) return !b;
|
||||
if(!b) return false;
|
||||
return std::strcmp(a,b)==0;
|
||||
inline bool operator()(const char* a, const char* b) const
|
||||
{
|
||||
if (!a) {
|
||||
return !b;
|
||||
}
|
||||
if (!b) {
|
||||
return false;
|
||||
}
|
||||
return std::strcmp(a, b) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -73,13 +83,13 @@ public:
|
||||
/** @name Access properties */
|
||||
//@{
|
||||
/// Get all properties of the class (including parent)
|
||||
void getPropertyList(std::vector<Property*> &List) const;
|
||||
void getPropertyList(std::vector<Property*>& List) const;
|
||||
/// get all properties with their names
|
||||
void getPropertyNamedList(std::vector<std::pair<const char*,Property*> > &List) const;
|
||||
void getPropertyNamedList(std::vector<std::pair<const char*, Property*>>& List) const;
|
||||
/// Get all properties of the class (including parent)
|
||||
void getPropertyMap(std::map<std::string,Property*> &Map) const;
|
||||
void getPropertyMap(std::map<std::string, Property*>& Map) const;
|
||||
/// Find a dynamic property by its name
|
||||
Property *getDynamicPropertyByName(const char* name) const;
|
||||
Property* getDynamicPropertyByName(const char* name) const;
|
||||
/*!
|
||||
Add a dynamic property of the type @a type and with the name @a name.
|
||||
@a Group gives the grouping name which appears in the property editor and
|
||||
@@ -97,22 +107,28 @@ public:
|
||||
addDynamicProperty(..., ..., "Base","blah", Prop_None, true, true);
|
||||
@endcode
|
||||
*/
|
||||
Property* addDynamicProperty(PropertyContainer &pc, const char* type, const char* name=nullptr, const char* group=nullptr,
|
||||
const char* doc=nullptr, short attr=0, bool ro=false, bool hidden=false);
|
||||
Property* addDynamicProperty(PropertyContainer& pc,
|
||||
const char* type,
|
||||
const char* name = nullptr,
|
||||
const char* group = nullptr,
|
||||
const char* doc = nullptr,
|
||||
short attr = 0,
|
||||
bool ro = false,
|
||||
bool hidden = false);
|
||||
/** Add a pre-existing property
|
||||
*
|
||||
* The property is not treated as dynamic, and will not trigger signal.
|
||||
*
|
||||
* @return Return false if there is a property exist with the same name.
|
||||
*/
|
||||
bool addProperty(Property *prop);
|
||||
bool addProperty(Property* prop);
|
||||
/*!
|
||||
Removes a dynamic property by name. Returns true if the property is part of the container, otherwise
|
||||
false is returned.
|
||||
Removes a dynamic property by name. Returns true if the property is part of the container,
|
||||
otherwise false is returned.
|
||||
*/
|
||||
bool removeDynamicProperty(const char* name);
|
||||
/// Remove pre-existing property, which will not be deleted.
|
||||
bool removeProperty(const Property *prop);
|
||||
bool removeProperty(const Property* prop);
|
||||
/// Get a list of all dynamic properties.
|
||||
std::vector<std::string> getDynamicPropertyNames() const;
|
||||
/// Get the name of a property
|
||||
@@ -124,72 +140,86 @@ public:
|
||||
/// Get the attributes of a property
|
||||
short getPropertyType(const Property* prop) const;
|
||||
/// Get the attributes of a named property
|
||||
short getPropertyType(const char *name) const;
|
||||
short getPropertyType(const char* name) const;
|
||||
/// Get the group name of a property
|
||||
const char* getPropertyGroup(const Property* prop) const;
|
||||
/// Get the group name of a named property
|
||||
const char* getPropertyGroup(const char *name) const;
|
||||
const char* getPropertyGroup(const char* name) const;
|
||||
/// Get the documentation of a property
|
||||
const char* getPropertyDocumentation(const Property* prop) const;
|
||||
/// Get the documentation of a named property
|
||||
const char* getPropertyDocumentation(const char *name) const;
|
||||
const char* getPropertyDocumentation(const char* name) const;
|
||||
//@}
|
||||
|
||||
/// Remove all properties
|
||||
void clear();
|
||||
|
||||
/// Get property count
|
||||
size_t size() const { return props.size(); }
|
||||
size_t size() const
|
||||
{
|
||||
return props.size();
|
||||
}
|
||||
|
||||
void save(const Property *prop, Base::Writer &writer) const;
|
||||
void save(const Property* prop, Base::Writer& writer) const;
|
||||
|
||||
Property *restore(PropertyContainer &pc,
|
||||
const char *PropName, const char *TypeName, Base::XMLReader &reader);
|
||||
Property* restore(PropertyContainer& pc,
|
||||
const char* PropName,
|
||||
const char* TypeName,
|
||||
Base::XMLReader& reader);
|
||||
|
||||
struct PropData {
|
||||
struct PropData
|
||||
{
|
||||
Property* property;
|
||||
std::string name;
|
||||
const char *pName;
|
||||
const char* pName;
|
||||
mutable std::string group;
|
||||
mutable std::string doc;
|
||||
short attr;
|
||||
bool readonly;
|
||||
bool hidden;
|
||||
|
||||
PropData(Property *prop=nullptr, std::string &&n=std::string(), const char *pn=nullptr,
|
||||
const char *g=nullptr, const char *d=nullptr, short a=0, bool ro=false, bool h=false)
|
||||
:property(prop),name(std::move(n)),pName(pn)
|
||||
,group(g?g:""),doc(d?d:""),attr(a),readonly(ro),hidden(h)
|
||||
PropData(Property* prop = nullptr,
|
||||
std::string&& n = std::string(),
|
||||
const char* pn = nullptr,
|
||||
const char* g = nullptr,
|
||||
const char* d = nullptr,
|
||||
short a = 0,
|
||||
bool ro = false,
|
||||
bool h = false)
|
||||
: property(prop)
|
||||
, name(std::move(n))
|
||||
, pName(pn)
|
||||
, group(g ? g : "")
|
||||
, doc(d ? d : "")
|
||||
, attr(a)
|
||||
, readonly(ro)
|
||||
, hidden(h)
|
||||
{}
|
||||
|
||||
const char *getName() const {
|
||||
return pName?pName:name.c_str();
|
||||
const char* getName() const
|
||||
{
|
||||
return pName ? pName : name.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
PropData getDynamicPropertyData(const Property* prop) const;
|
||||
|
||||
bool changeDynamicProperty(const Property *prop, const char *group, const char *doc);
|
||||
bool changeDynamicProperty(const Property* prop, const char* group, const char* doc);
|
||||
|
||||
private:
|
||||
std::string getUniquePropertyName(PropertyContainer &pc, const char *Name) const;
|
||||
std::string getUniquePropertyName(PropertyContainer& pc, const char* Name) const;
|
||||
|
||||
private:
|
||||
bmi::multi_index_container<
|
||||
PropData,
|
||||
bmi::indexed_by<
|
||||
bmi::hashed_unique<
|
||||
bmi::const_mem_fun<PropData, const char*, &PropData::getName>,
|
||||
CStringHasher,
|
||||
CStringHasher
|
||||
>,
|
||||
bmi::hashed_unique<
|
||||
bmi::member<PropData, Property*, &PropData::property>
|
||||
>
|
||||
>
|
||||
> props;
|
||||
bmi::hashed_unique<bmi::const_mem_fun<PropData, const char*, &PropData::getName>,
|
||||
CStringHasher,
|
||||
CStringHasher>,
|
||||
bmi::hashed_unique<bmi::member<PropData, Property*, &PropData::property>>>>
|
||||
props;
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_DYNAMICPROPERTY_H
|
||||
#endif // APP_DYNAMICPROPERTY_H
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
|
||||
|
||||
FC_LOG_LEVEL_INIT("ElementMap", true, 2);// NOLINT
|
||||
FC_LOG_LEVEL_INIT("ElementMap", true, 2); // NOLINT
|
||||
|
||||
namespace Data
|
||||
{
|
||||
@@ -104,7 +104,8 @@ void ElementMap::beforeSave(const ::App::StringHasherRef& hasherRef) const
|
||||
}
|
||||
}
|
||||
|
||||
void ElementMap::save(std::ostream& stream, int index,
|
||||
void ElementMap::save(std::ostream& stream,
|
||||
int index,
|
||||
const std::map<const ElementMap*, int>& childMapSet,
|
||||
const std::map<QByteArray, int>& postfixMap) const
|
||||
{
|
||||
@@ -121,7 +122,7 @@ void ElementMap::save(std::ostream& stream, int index,
|
||||
if (child.elementMap) {
|
||||
auto it = childMapSet.find(child.elementMap.get());
|
||||
if (it == childMapSet.end() || it->second == 0) {
|
||||
FC_ERR("Invalid child element map");// NOLINT
|
||||
FC_ERR("Invalid child element map"); // NOLINT
|
||||
}
|
||||
else {
|
||||
mapIndex = it->second;
|
||||
@@ -240,7 +241,7 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
|
||||
int count = 0;
|
||||
std::string tmp;
|
||||
if (!(stream >> id >> tmp >> count) || tmp != "PostfixCount") {
|
||||
FC_THROWM(Base::RuntimeError, msg);// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, msg); // NOLINT
|
||||
}
|
||||
|
||||
auto& map = _idToElementMap[id];
|
||||
@@ -258,7 +259,7 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
|
||||
std::vector<ElementMapPtr> childMaps;
|
||||
count = 0;
|
||||
if (!(stream >> tmp >> count) || tmp != "MapCount" || count == 0) {
|
||||
FC_THROWM(Base::RuntimeError, msg);// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, msg); // NOLINT
|
||||
}
|
||||
childMaps.reserve(count - 1);
|
||||
for (int i = 0; i < count - 1; ++i) {
|
||||
@@ -269,7 +270,8 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
|
||||
return restore(hasherRef, stream, childMaps, postfixes);
|
||||
}
|
||||
|
||||
ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream& stream,
|
||||
ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef,
|
||||
std::istream& stream,
|
||||
std::vector<ElementMapPtr>& childMaps,
|
||||
const std::vector<std::string>& postfixes)
|
||||
{
|
||||
@@ -281,14 +283,14 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
|
||||
int typeCount = 0;
|
||||
unsigned id = 0;
|
||||
if (!(stream >> tmp >> index >> id >> typeCount) || tmp != "ElementMap") {
|
||||
FC_THROWM(Base::RuntimeError, msg);// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, msg); // NOLINT
|
||||
}
|
||||
|
||||
auto& map = _idToElementMap[id];
|
||||
if (map) {
|
||||
while (tmp != "EndMap") {
|
||||
if (!std::getline(stream, tmp)) {
|
||||
FC_THROWM(Base::RuntimeError, "unexpected end of child element map");// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, "unexpected end of child element map"); // NOLINT
|
||||
}
|
||||
}
|
||||
return map;
|
||||
@@ -303,12 +305,12 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
|
||||
for (int i = 0; i < typeCount; ++i) {
|
||||
int outerCount = 0;
|
||||
if (!(stream >> tmp)) {
|
||||
FC_THROWM(Base::RuntimeError, "missing element type");// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, "missing element type"); // NOLINT
|
||||
}
|
||||
IndexedName idx(tmp.c_str(), 1);
|
||||
|
||||
if (!(stream >> tmp >> outerCount) || tmp != "ChildCount") {
|
||||
FC_THROWM(Base::RuntimeError, "missing element child count");// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, "missing element child count"); // NOLINT
|
||||
}
|
||||
|
||||
auto& indices = this->indexedNames[idx.getType()];
|
||||
@@ -319,16 +321,16 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
|
||||
long tag = 0;
|
||||
int mapIndex = 0;
|
||||
if (!(stream >> cIndex >> offset >> count >> tag >> mapIndex >> tmp)) {
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element child");// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element child"); // NOLINT
|
||||
}
|
||||
if (cIndex < 0) {
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element child index");// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element child index"); // NOLINT
|
||||
}
|
||||
if (offset < 0) {
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element child offset");// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element child offset"); // NOLINT
|
||||
}
|
||||
if (mapIndex >= index || mapIndex < 0 || mapIndex > (int)childMaps.size()) {
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element child map index");// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element child map index"); // NOLINT
|
||||
}
|
||||
auto& child = indices.children[cIndex + offset + count];
|
||||
child.indexedName = IndexedName::fromConst(idx.getType(), cIndex);
|
||||
@@ -346,7 +348,7 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
|
||||
this->childElementSize += child.count;
|
||||
|
||||
if (!(stream >> tmp)) {
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element child string id");// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element child string id"); // NOLINT
|
||||
}
|
||||
|
||||
tokens.clear();
|
||||
@@ -371,7 +373,7 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
|
||||
}
|
||||
|
||||
if (!(stream >> tmp >> outerCount) || tmp != "NameCount") {
|
||||
FC_THROWM(Base::RuntimeError, "missing element name outerCount");// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, "missing element name outerCount"); // NOLINT
|
||||
}
|
||||
|
||||
boost::io::ios_flags_saver ifs(stream);
|
||||
@@ -384,7 +386,7 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
|
||||
int innerCount = 0;
|
||||
while (true) {
|
||||
if (!(stream >> tmp)) {
|
||||
FC_THROWM(Base::RuntimeError, "Failed to read element name");// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, "Failed to read element name"); // NOLINT
|
||||
}
|
||||
if (tmp == "0") {
|
||||
break;
|
||||
@@ -396,7 +398,7 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
|
||||
tokens.clear();
|
||||
boost::split(tokens, tmp, boost::is_any_of("."));
|
||||
if (tokens.size() < 2) {
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element entry");// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element entry"); // NOLINT
|
||||
}
|
||||
|
||||
int offset = 1;
|
||||
@@ -406,12 +408,12 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
|
||||
switch (tokens[0][0]) {
|
||||
case ':': {
|
||||
if (tokens.size() < 3) {
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element entry");// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element entry"); // NOLINT
|
||||
}
|
||||
++offset;
|
||||
long elementNameIndex = strtol(tokens[0].c_str() + 1, nullptr, hexBase);
|
||||
if (elementNameIndex <= 0 || elementNameIndex > (int)postfixes.size()) {
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element name index");// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element name index"); // NOLINT
|
||||
}
|
||||
long elementIndex = strtol(tokens[1].c_str(), nullptr, hexBase);
|
||||
ref->name = MappedName(
|
||||
@@ -427,7 +429,7 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
|
||||
ref->name = MappedName(tokens[0].c_str() + 1);
|
||||
break;
|
||||
default:
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element name marker");// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, "Invalid element name marker"); // NOLINT
|
||||
}
|
||||
|
||||
if (tokens[offset] != "0") {
|
||||
@@ -473,31 +475,34 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
|
||||
}
|
||||
}
|
||||
if (hasherWarn) {
|
||||
FC_WARN(hasherWarn);// NOLINT
|
||||
FC_WARN(hasherWarn); // NOLINT
|
||||
}
|
||||
if (hasherIDWarn) {
|
||||
FC_WARN(hasherIDWarn);// NOLINT
|
||||
FC_WARN(hasherIDWarn); // NOLINT
|
||||
}
|
||||
if (postfixWarn) {
|
||||
FC_WARN(postfixWarn);// NOLINT
|
||||
FC_WARN(postfixWarn); // NOLINT
|
||||
}
|
||||
if (childSIDWarn) {
|
||||
FC_WARN(childSIDWarn);// NOLINT
|
||||
FC_WARN(childSIDWarn); // NOLINT
|
||||
}
|
||||
|
||||
if (!(stream >> tmp) || tmp != "EndMap") {
|
||||
FC_THROWM(Base::RuntimeError, "unexpected end of child element map");// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, "unexpected end of child element map"); // NOLINT
|
||||
}
|
||||
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
MappedName ElementMap::addName(MappedName& name, const IndexedName& idx, const ElementIDRefs& sids,
|
||||
bool overwrite, IndexedName* existing)
|
||||
MappedName ElementMap::addName(MappedName& name,
|
||||
const IndexedName& idx,
|
||||
const ElementIDRefs& sids,
|
||||
bool overwrite,
|
||||
IndexedName* existing)
|
||||
{
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
if (name.find("#") >= 0 && name.findTagInElementName() < 0) {
|
||||
FC_ERR("missing tag postfix " << name);// NOLINT
|
||||
FC_ERR("missing tag postfix " << name); // NOLINT
|
||||
}
|
||||
}
|
||||
while (true) {
|
||||
@@ -505,14 +510,14 @@ MappedName ElementMap::addName(MappedName& name, const IndexedName& idx, const E
|
||||
erase(idx);
|
||||
}
|
||||
auto ret = mappedNames.insert(std::make_pair(name, idx));
|
||||
if (ret.second) { // element just inserted did not exist yet in the map
|
||||
ret.first->first.compact();// FIXME see MappedName.cpp
|
||||
if (ret.second) { // element just inserted did not exist yet in the map
|
||||
ret.first->first.compact(); // FIXME see MappedName.cpp
|
||||
mappedRef(idx).append(ret.first->first, sids);
|
||||
FC_TRACE(idx << " -> " << name);// NOLINT
|
||||
FC_TRACE(idx << " -> " << name); // NOLINT
|
||||
return ret.first->first;
|
||||
}
|
||||
if (ret.first->second == idx) {
|
||||
FC_TRACE("duplicate " << idx << " -> " << name);// NOLINT
|
||||
FC_TRACE("duplicate " << idx << " -> " << name); // NOLINT
|
||||
return ret.first->first;
|
||||
}
|
||||
if (!overwrite) {
|
||||
@@ -526,7 +531,8 @@ MappedName ElementMap::addName(MappedName& name, const IndexedName& idx, const E
|
||||
};
|
||||
}
|
||||
|
||||
void ElementMap::addPostfix(const QByteArray& postfix, std::map<QByteArray, int>& postfixMap,
|
||||
void ElementMap::addPostfix(const QByteArray& postfix,
|
||||
std::map<QByteArray, int>& postfixMap,
|
||||
std::vector<QByteArray>& postfixes)
|
||||
{
|
||||
if (postfix.isEmpty()) {
|
||||
@@ -539,8 +545,11 @@ void ElementMap::addPostfix(const QByteArray& postfix, std::map<QByteArray, int>
|
||||
}
|
||||
}
|
||||
|
||||
MappedName ElementMap::setElementName(const IndexedName& element, const MappedName& name,
|
||||
long masterTag, const ElementIDRefs* sid, bool overwrite)
|
||||
MappedName ElementMap::setElementName(const IndexedName& element,
|
||||
const MappedName& name,
|
||||
long masterTag,
|
||||
const ElementIDRefs* sid,
|
||||
bool overwrite)
|
||||
{
|
||||
if (!element) {
|
||||
throw Base::ValueError("Invalid input");
|
||||
@@ -553,13 +562,13 @@ MappedName ElementMap::setElementName(const IndexedName& element, const MappedNa
|
||||
for (int i = 0, count = name.size(); i < count; ++i) {
|
||||
char check = name[i];
|
||||
if (check == '.' || (std::isspace((int)check) != 0)) {
|
||||
FC_THROWM(Base::RuntimeError, "Illegal character in mapped name: " << name);// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, "Illegal character in mapped name: " << name); // NOLINT
|
||||
}
|
||||
}
|
||||
for (const char* readChar = element.getType(); *readChar != 0; ++readChar) {
|
||||
char check = *readChar;
|
||||
if (check == '.' || (std::isspace((int)check) != 0)) {
|
||||
FC_THROWM(Base::RuntimeError,// NOLINT
|
||||
FC_THROWM(Base::RuntimeError, // NOLINT
|
||||
"Illegal character in element name: " << element);
|
||||
}
|
||||
}
|
||||
@@ -586,7 +595,7 @@ MappedName ElementMap::setElementName(const IndexedName& element, const MappedNa
|
||||
}
|
||||
const int maxAttempts {100};
|
||||
if (++i == maxAttempts) {
|
||||
FC_ERR("unresolved duplicate element mapping '"// NOLINT
|
||||
FC_ERR("unresolved duplicate element mapping '" // NOLINT
|
||||
<< name << ' ' << element << '/' << existing);
|
||||
return name;
|
||||
}
|
||||
@@ -602,9 +611,14 @@ MappedName ElementMap::setElementName(const IndexedName& element, const MappedNa
|
||||
}
|
||||
|
||||
// try to hash element name while preserving the source tag
|
||||
void ElementMap::encodeElementName(char element_type, MappedName& name, std::ostringstream& ss,
|
||||
ElementIDRefs* sids, long masterTag, const char* postfix,
|
||||
long tag, bool forceTag) const
|
||||
void ElementMap::encodeElementName(char element_type,
|
||||
MappedName& name,
|
||||
std::ostringstream& ss,
|
||||
ElementIDRefs* sids,
|
||||
long masterTag,
|
||||
const char* postfix,
|
||||
long tag,
|
||||
bool forceTag) const
|
||||
{
|
||||
if (postfix && (postfix[0] != 0)) {
|
||||
if (!boost::starts_with(postfix, ELEMENT_MAP_PREFIX)) {
|
||||
@@ -715,26 +729,30 @@ MappedName ElementMap::dehashElementName(const MappedName& name) const
|
||||
auto sid = this->hasher->getID(id);
|
||||
if (!sid) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_TRACE)) {
|
||||
FC_WARN("failed to find hash id " << id);// NOLINT
|
||||
FC_WARN("failed to find hash id " << id); // NOLINT
|
||||
}
|
||||
else {
|
||||
FC_LOG("failed to find hash id " << id);// NOLINT
|
||||
FC_LOG("failed to find hash id " << id); // NOLINT
|
||||
}
|
||||
return name;
|
||||
}
|
||||
if (sid.isHashed()) {
|
||||
FC_LOG("cannot de-hash id " << id);// NOLINT
|
||||
FC_LOG("cannot de-hash id " << id); // NOLINT
|
||||
return name;
|
||||
}
|
||||
MappedName ret(sid);
|
||||
// sid.toString());// FIXME .toString() was missing in original function. is this correct?
|
||||
FC_TRACE("de-hash " << name << " -> " << ret);// NOLINT
|
||||
// sid.toString());// FIXME .toString() was missing in original function. is this
|
||||
// correct?
|
||||
FC_TRACE("de-hash " << name << " -> " << ret); // NOLINT
|
||||
return ret;
|
||||
}
|
||||
|
||||
MappedName ElementMap::renameDuplicateElement(int index, const IndexedName& element,
|
||||
const IndexedName& element2, const MappedName& name,
|
||||
ElementIDRefs& sids, long masterTag) const
|
||||
MappedName ElementMap::renameDuplicateElement(int index,
|
||||
const IndexedName& element,
|
||||
const IndexedName& element2,
|
||||
const MappedName& name,
|
||||
ElementIDRefs& sids,
|
||||
long masterTag) const
|
||||
{
|
||||
int idx {0};
|
||||
#ifdef FC_DEBUG
|
||||
@@ -751,7 +769,7 @@ MappedName ElementMap::renameDuplicateElement(int index, const IndexedName& elem
|
||||
MappedName renamed(name);
|
||||
encodeElementName(element.getType()[0], renamed, ss, &sids, masterTag);
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("duplicate element mapping '"// NOLINT
|
||||
FC_WARN("duplicate element mapping '" // NOLINT
|
||||
<< name << " -> " << renamed << ' ' << element << '/' << element2);
|
||||
}
|
||||
return renamed;
|
||||
@@ -1008,13 +1026,20 @@ void ElementMap::hashChildMaps(long masterTag)
|
||||
.findTagInElementName(&tag, &len, nullptr, nullptr, false, false);
|
||||
// TODO: What is this 10?
|
||||
if (pos > 10) {
|
||||
MappedName postfix = hashElementName(
|
||||
MappedName::fromRawData(child.postfix.constData(), pos), child.sids);
|
||||
MappedName postfix =
|
||||
hashElementName(MappedName::fromRawData(child.postfix.constData(), pos),
|
||||
child.sids);
|
||||
ss.str("");
|
||||
ss << MAPPED_CHILD_ELEMENTS_PREFIX << postfix;
|
||||
MappedName tmp;
|
||||
encodeElementName(
|
||||
child.indexedName[0], tmp, ss, nullptr, masterTag, nullptr, child.tag, true);
|
||||
encodeElementName(child.indexedName[0],
|
||||
tmp,
|
||||
ss,
|
||||
nullptr,
|
||||
masterTag,
|
||||
nullptr,
|
||||
child.tag,
|
||||
true);
|
||||
this->childElements.remove(child.postfix);
|
||||
child.postfix = tmp.toBytes();
|
||||
this->childElements[child.postfix].childMap = &child;
|
||||
@@ -1152,7 +1177,7 @@ void ElementMap::addChildElements(long masterTag, const std::vector<MappedChildE
|
||||
for (auto& child : expansion.empty() ? children : expansion) {
|
||||
if (!child.indexedName || (child.count == 0)) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_ERR("invalid mapped child element");// NOLINT
|
||||
FC_ERR("invalid mapped child element"); // NOLINT
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -1195,15 +1220,20 @@ void ElementMap::addChildElements(long masterTag, const std::vector<MappedChildE
|
||||
if (!name) {
|
||||
if ((child.tag == 0) || child.tag == masterTag) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("unmapped element");// NOLINT
|
||||
FC_WARN("unmapped element"); // NOLINT
|
||||
}
|
||||
continue;
|
||||
}
|
||||
name = MappedName(childIdx);
|
||||
}
|
||||
ss.str("");
|
||||
encodeElementName(
|
||||
idx[0], name, ss, &sids, masterTag, child.postfix.constData(), child.tag);
|
||||
encodeElementName(idx[0],
|
||||
name,
|
||||
ss,
|
||||
&sids,
|
||||
masterTag,
|
||||
child.postfix.constData(),
|
||||
child.tag);
|
||||
setElementName(idx, name, masterTag, &sids);
|
||||
}
|
||||
continue;
|
||||
@@ -1231,19 +1261,20 @@ void ElementMap::addChildElements(long masterTag, const std::vector<MappedChildE
|
||||
|
||||
entry = &childElements[tmp.toBytes()];
|
||||
if (entry->childMap) {
|
||||
FC_ERR("duplicate mapped child element");// NOLINT
|
||||
FC_ERR("duplicate mapped child element"); // NOLINT
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
auto& indices = this->indexedNames[child.indexedName.getType()];
|
||||
auto res = indices.children.emplace(
|
||||
child.indexedName.getIndex() + child.offset + child.count, child);
|
||||
auto res =
|
||||
indices.children.emplace(child.indexedName.getIndex() + child.offset + child.count,
|
||||
child);
|
||||
if (!res.second) {
|
||||
if (!entry->childMap) {
|
||||
this->childElements.remove(tmp.toBytes());
|
||||
}
|
||||
FC_ERR("duplicate mapped child element");// NOLINT
|
||||
FC_ERR("duplicate mapped child element"); // NOLINT
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1293,7 +1324,9 @@ std::vector<MappedElement> ElementMap::getAll() const
|
||||
return ret;
|
||||
}
|
||||
|
||||
long ElementMap::getElementHistory(const MappedName& name, long masterTag, MappedName* original,
|
||||
long ElementMap::getElementHistory(const MappedName& name,
|
||||
long masterTag,
|
||||
MappedName* original,
|
||||
std::vector<MappedName>* history) const
|
||||
{
|
||||
long tag = 0;
|
||||
@@ -1321,7 +1354,7 @@ long ElementMap::getElementHistory(const MappedName& name, long masterTag, Mappe
|
||||
|
||||
while (true) {
|
||||
if ((len == 0) || len > pos) {
|
||||
FC_WARN("invalid name length " << name);// NOLINT
|
||||
FC_WARN("invalid name length " << name); // NOLINT
|
||||
return 0;
|
||||
}
|
||||
bool deHashed = false;
|
||||
@@ -1440,4 +1473,4 @@ void ElementMap::traceElement(const MappedName& name, long masterTag, TraceCallb
|
||||
}
|
||||
|
||||
|
||||
}// Namespace Data
|
||||
} // Namespace Data
|
||||
|
||||
@@ -46,17 +46,17 @@ class ElementMap;
|
||||
using ElementMapPtr = std::shared_ptr<ElementMap>;
|
||||
|
||||
/** Element trace callback
|
||||
*
|
||||
* The callback has the following call signature
|
||||
* (const std::string &name, size_t offset, long encodedTag, long tag) -> bool
|
||||
*
|
||||
* @param name: the current element name.
|
||||
* @param offset: the offset skipping the encoded element name for the next iteration.
|
||||
* @param encodedTag: the tag encoded inside the current element, which is usually the tag
|
||||
* of the previous step in the shape history.
|
||||
* @param tag: the tag of the current shape element.
|
||||
*
|
||||
* @sa traceElement()
|
||||
*
|
||||
* The callback has the following call signature
|
||||
* (const std::string &name, size_t offset, long encodedTag, long tag) -> bool
|
||||
*
|
||||
* @param name: the current element name.
|
||||
* @param offset: the offset skipping the encoded element name for the next iteration.
|
||||
* @param encodedTag: the tag encoded inside the current element, which is usually the tag
|
||||
* of the previous step in the shape history.
|
||||
* @param tag: the tag of the current shape element.
|
||||
*
|
||||
* @sa traceElement()
|
||||
*/
|
||||
typedef std::function<bool(const MappedName&, int, long, long)> TraceCallback;
|
||||
|
||||
@@ -68,13 +68,14 @@ typedef std::function<bool(const MappedName&, int, long, long)> TraceCallback;
|
||||
* possibly a recursive elementmap
|
||||
* `mappedNames` maps a MappedName to a specific IndexedName.
|
||||
*/
|
||||
class AppExport ElementMap: public std::enable_shared_from_this<ElementMap> //TODO can remove shared_from_this?
|
||||
class AppExport ElementMap
|
||||
: public std::enable_shared_from_this<ElementMap> // TODO can remove shared_from_this?
|
||||
{
|
||||
public:
|
||||
/** Default constructor: hooks internal functions to \c signalSaveDocument and
|
||||
* \c signalStartRestoreDocument. This is related to the save and restore process
|
||||
* of the map.
|
||||
*/
|
||||
*/
|
||||
ElementMap();
|
||||
|
||||
/** Ensures that naming is properly assigned. It then marks as "used" all the StringID
|
||||
@@ -82,14 +83,14 @@ public:
|
||||
* as a parameter. Finally do this recursively for all childEelementMaps as well.
|
||||
*
|
||||
* @param hasherRef where all the StringID needed to build the map are stored.
|
||||
*/
|
||||
*/
|
||||
// FIXME this should be made part of \c save, to achieve symmetry with the restore method
|
||||
void beforeSave(const ::App::StringHasherRef& hasherRef) const;
|
||||
|
||||
/** Serialize this map. Calls \c collectChildMaps to get \c childMapSet and
|
||||
* \c postfixMap, then calls the other (private) save function with those parameters.
|
||||
* @param stream: serialized stream
|
||||
*/
|
||||
*/
|
||||
void save(std::ostream& stream) const;
|
||||
|
||||
/** Deserialize and restore this map. This function restores \c childMaps and
|
||||
@@ -97,7 +98,7 @@ public:
|
||||
* parameters.
|
||||
* @param hasherRef: where all the StringIDs are stored
|
||||
* @param stream: stream to deserialize
|
||||
*/
|
||||
*/
|
||||
ElementMapPtr restore(::App::StringHasherRef hasherRef, std::istream& stream);
|
||||
|
||||
|
||||
@@ -196,9 +197,10 @@ public:
|
||||
|
||||
std::vector<MappedElement> getAll() const;
|
||||
|
||||
long getElementHistory(const MappedName & name,
|
||||
long getElementHistory(const MappedName& name,
|
||||
long masterTag,
|
||||
MappedName *original=nullptr, std::vector<MappedName> *history=nullptr) const;
|
||||
MappedName* original = nullptr,
|
||||
std::vector<MappedName>* history = nullptr) const;
|
||||
|
||||
/** Iterate through the history of the give element name with a given callback
|
||||
*
|
||||
@@ -214,8 +216,10 @@ private:
|
||||
* @param stream: serialized stream
|
||||
* @param childMapSet: where all child element maps are stored
|
||||
* @param postfixMap. where all postfixes are stored
|
||||
*/
|
||||
void save(std::ostream& stream, int index, const std::map<const ElementMap*, int>& childMapSet,
|
||||
*/
|
||||
void save(std::ostream& stream,
|
||||
int index,
|
||||
const std::map<const ElementMap*, int>& childMapSet,
|
||||
const std::map<QByteArray, int>& postfixMap) const;
|
||||
|
||||
/** Deserialize and restore this map.
|
||||
@@ -223,8 +227,9 @@ private:
|
||||
* @param stream: stream to deserialize
|
||||
* @param childMaps: where all child element maps are stored
|
||||
* @param postfixes. where all postfixes are stored
|
||||
*/
|
||||
ElementMapPtr restore(::App::StringHasherRef hasherRef, std::istream& stream,
|
||||
*/
|
||||
ElementMapPtr restore(::App::StringHasherRef hasherRef,
|
||||
std::istream& stream,
|
||||
std::vector<ElementMapPtr>& childMaps,
|
||||
const std::vector<std::string>& postfixes);
|
||||
|
||||
@@ -237,20 +242,27 @@ private:
|
||||
* associated with another indexedName, set \c existing to that indexedname
|
||||
* @return the name just added, or an empty name if it wasn't added.
|
||||
*/
|
||||
MappedName addName(MappedName& name, const IndexedName& idx, const ElementIDRefs& sids,
|
||||
bool overwrite, IndexedName* existing);
|
||||
MappedName addName(MappedName& name,
|
||||
const IndexedName& idx,
|
||||
const ElementIDRefs& sids,
|
||||
bool overwrite,
|
||||
IndexedName* existing);
|
||||
|
||||
/** Utility function that adds \c postfix to \c postfixMap, and to \c postfixes
|
||||
* if it was not present in the map.
|
||||
*/
|
||||
static void addPostfix(const QByteArray& postfix, std::map<QByteArray, int>& postfixMap,
|
||||
*/
|
||||
static void addPostfix(const QByteArray& postfix,
|
||||
std::map<QByteArray, int>& postfixMap,
|
||||
std::vector<QByteArray>& postfixes);
|
||||
|
||||
/* Note: the original proc passed `ComplexGeoData& master` for getting the `Tag`,
|
||||
* now it just passes `long masterTag`.*/
|
||||
MappedName renameDuplicateElement(int index, const IndexedName& element,
|
||||
const IndexedName& element2, const MappedName& name,
|
||||
ElementIDRefs& sids, long masterTag) const;
|
||||
MappedName renameDuplicateElement(int index,
|
||||
const IndexedName& element,
|
||||
const IndexedName& element2,
|
||||
const MappedName& name,
|
||||
ElementIDRefs& sids,
|
||||
long masterTag) const;
|
||||
|
||||
/** Convenience method to hash the main element name
|
||||
*
|
||||
@@ -263,7 +275,7 @@ private:
|
||||
/// Reverse hashElementName()
|
||||
MappedName dehashElementName(const MappedName& name) const;
|
||||
|
||||
//FIXME duplicate code? as in copy/paste
|
||||
// FIXME duplicate code? as in copy/paste
|
||||
const MappedNameRef* findMappedRef(const IndexedName& idx) const;
|
||||
MappedNameRef* findMappedRef(const IndexedName& idx);
|
||||
|
||||
@@ -313,6 +325,6 @@ public:
|
||||
};
|
||||
|
||||
|
||||
}// namespace Data
|
||||
} // namespace Data
|
||||
|
||||
#endif// DATA_ELEMENTMAP_H
|
||||
#endif // DATA_ELEMENTMAP_H
|
||||
|
||||
@@ -4,96 +4,119 @@
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
|
||||
const char *Data::isMappedElement(const char *name) {
|
||||
if(name && boost::starts_with(name, ELEMENT_MAP_PREFIX))
|
||||
const char* Data::isMappedElement(const char* name)
|
||||
{
|
||||
if (name && boost::starts_with(name, ELEMENT_MAP_PREFIX)) {
|
||||
return name + ELEMENT_MAP_PREFIX_SIZE;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string Data::newElementName(const char *name) {
|
||||
if(!name)
|
||||
std::string Data::newElementName(const char* name)
|
||||
{
|
||||
if (!name) {
|
||||
return {};
|
||||
const char *dot = strrchr(name,'.');
|
||||
if(!dot || dot==name)
|
||||
}
|
||||
const char* dot = strrchr(name, '.');
|
||||
if (!dot || dot == name) {
|
||||
return name;
|
||||
const char *c = dot-1;
|
||||
for(;c!=name;--c) {
|
||||
if(*c == '.') {
|
||||
}
|
||||
const char* c = dot - 1;
|
||||
for (; c != name; --c) {
|
||||
if (*c == '.') {
|
||||
++c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(isMappedElement(c))
|
||||
return std::string(name,dot-name);
|
||||
if (isMappedElement(c)) {
|
||||
return std::string(name, dot - name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string Data::oldElementName(const char *name) {
|
||||
if(!name)
|
||||
std::string Data::oldElementName(const char* name)
|
||||
{
|
||||
if (!name) {
|
||||
return {};
|
||||
const char *dot = strrchr(name,'.');
|
||||
if(!dot || dot==name)
|
||||
}
|
||||
const char* dot = strrchr(name, '.');
|
||||
if (!dot || dot == name) {
|
||||
return name;
|
||||
const char *c = dot-1;
|
||||
for(;c!=name;--c) {
|
||||
if(*c == '.') {
|
||||
}
|
||||
const char* c = dot - 1;
|
||||
for (; c != name; --c) {
|
||||
if (*c == '.') {
|
||||
++c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(isMappedElement(c))
|
||||
return std::string(name,c-name)+(dot+1);
|
||||
if (isMappedElement(c)) {
|
||||
return std::string(name, c - name) + (dot + 1);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string Data::noElementName(const char *name) {
|
||||
if(!name)
|
||||
std::string Data::noElementName(const char* name)
|
||||
{
|
||||
if (!name) {
|
||||
return {};
|
||||
}
|
||||
auto element = findElementName(name);
|
||||
if(element)
|
||||
return std::string(name,element-name);
|
||||
if (element) {
|
||||
return std::string(name, element - name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
const char *Data::findElementName(const char *subname) {
|
||||
const char* Data::findElementName(const char* subname)
|
||||
{
|
||||
// skip leading dots
|
||||
while(subname && subname[0] == '.')
|
||||
while (subname && subname[0] == '.') {
|
||||
++subname;
|
||||
if(!subname || !subname[0] || isMappedElement(subname))
|
||||
}
|
||||
if (!subname || !subname[0] || isMappedElement(subname)) {
|
||||
return subname;
|
||||
const char *dot = strrchr(subname,'.');
|
||||
if(!dot)
|
||||
}
|
||||
const char* dot = strrchr(subname, '.');
|
||||
if (!dot) {
|
||||
return subname;
|
||||
const char *element = dot+1;
|
||||
if(dot==subname || isMappedElement(element))
|
||||
}
|
||||
const char* element = dot + 1;
|
||||
if (dot == subname || isMappedElement(element)) {
|
||||
return element;
|
||||
for(--dot;dot!=subname;--dot) {
|
||||
if(*dot == '.') {
|
||||
}
|
||||
for (--dot; dot != subname; --dot) {
|
||||
if (*dot == '.') {
|
||||
++dot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(isMappedElement(dot))
|
||||
if (isMappedElement(dot)) {
|
||||
return dot;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
bool Data::hasMissingElement(const char *subname) {
|
||||
if(!subname)
|
||||
bool Data::hasMissingElement(const char* subname)
|
||||
{
|
||||
if (!subname) {
|
||||
return false;
|
||||
auto dot = strrchr(subname,'.');
|
||||
if(dot)
|
||||
subname = dot+1;
|
||||
}
|
||||
auto dot = strrchr(subname, '.');
|
||||
if (dot) {
|
||||
subname = dot + 1;
|
||||
}
|
||||
return boost::starts_with(subname, MISSING_PREFIX);
|
||||
}
|
||||
|
||||
const char *Data::hasMappedElementName(const char *subname) {
|
||||
const char* Data::hasMappedElementName(const char* subname)
|
||||
{
|
||||
return isMappedElement(findElementName(subname));
|
||||
}
|
||||
|
||||
const std::string Data::indexSuffix(int index, const char *label)
|
||||
const std::string Data::indexSuffix(int index, const char* label)
|
||||
{
|
||||
if ( index < 2 ) { // Don't add a suffix for item #1, begin appending at 2
|
||||
if (index < 2) { // Don't add a suffix for item #1, begin appending at 2
|
||||
return {""};
|
||||
}
|
||||
std::string name(label);
|
||||
|
||||
@@ -18,10 +18,10 @@ struct ElementNamePair
|
||||
|
||||
ElementNamePair() = default;
|
||||
|
||||
ElementNamePair(std::string newNameStr, std::string oldNameStr) :
|
||||
newName(std::move(newNameStr)), oldName(std::move(oldNameStr))
|
||||
{
|
||||
}
|
||||
ElementNamePair(std::string newNameStr, std::string oldNameStr)
|
||||
: newName(std::move(newNameStr))
|
||||
, oldName(std::move(oldNameStr))
|
||||
{}
|
||||
|
||||
bool operator==(const ElementNamePair& other) const
|
||||
{
|
||||
@@ -34,7 +34,7 @@ struct ElementNamePair
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace App
|
||||
|
||||
// clang-format off
|
||||
namespace Data
|
||||
@@ -101,4 +101,4 @@ AppExport const std::string indexSuffix(int index, const char *label=ELEMENT_MAP
|
||||
} // namespace Data
|
||||
// clang-format on
|
||||
|
||||
#endif // ELEMENT_NAMING_UTILS_H
|
||||
#endif // ELEMENT_NAMING_UTILS_H
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
# include <cassert>
|
||||
# include <cstring>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
#include <Base/Exception.h>
|
||||
@@ -32,17 +32,23 @@
|
||||
|
||||
using namespace App;
|
||||
|
||||
namespace {
|
||||
struct StringCopy : public Enumeration::Object {
|
||||
explicit StringCopy(const char* str) : d(str) {
|
||||
}
|
||||
const char* data() const override {
|
||||
namespace
|
||||
{
|
||||
struct StringCopy: public Enumeration::Object
|
||||
{
|
||||
explicit StringCopy(const char* str)
|
||||
: d(str)
|
||||
{}
|
||||
const char* data() const override
|
||||
{
|
||||
return d.data();
|
||||
}
|
||||
bool isEqual(const char* str) const override {
|
||||
bool isEqual(const char* str) const override
|
||||
{
|
||||
return d == str;
|
||||
}
|
||||
bool isCustom() const override {
|
||||
bool isCustom() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -50,43 +56,47 @@ private:
|
||||
std::string d;
|
||||
};
|
||||
|
||||
struct StringView : public Enumeration::Object {
|
||||
explicit StringView(const char* str) : d(str) {
|
||||
}
|
||||
const char* data() const override {
|
||||
struct StringView: public Enumeration::Object
|
||||
{
|
||||
explicit StringView(const char* str)
|
||||
: d(str)
|
||||
{}
|
||||
const char* data() const override
|
||||
{
|
||||
return d.data();
|
||||
}
|
||||
bool isEqual(const char* str) const override {
|
||||
bool isEqual(const char* str) const override
|
||||
{
|
||||
return d == str;
|
||||
}
|
||||
bool isCustom() const override {
|
||||
bool isCustom() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string_view d;
|
||||
};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Enumeration::Enumeration()
|
||||
: _index(0)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
Enumeration::Enumeration(const Enumeration &other)
|
||||
Enumeration::Enumeration(const Enumeration& other)
|
||||
{
|
||||
enumArray = other.enumArray;
|
||||
_index = other._index;
|
||||
}
|
||||
|
||||
Enumeration::Enumeration(const char *valStr)
|
||||
Enumeration::Enumeration(const char* valStr)
|
||||
: _index(0)
|
||||
{
|
||||
enumArray.push_back(std::make_shared<StringCopy>(valStr));
|
||||
setValue(valStr);
|
||||
}
|
||||
|
||||
Enumeration::Enumeration(const char **list, const char *valStr)
|
||||
Enumeration::Enumeration(const char** list, const char* valStr)
|
||||
: _index(0)
|
||||
{
|
||||
while (list && *list) {
|
||||
@@ -101,14 +111,15 @@ Enumeration::~Enumeration()
|
||||
enumArray.clear();
|
||||
}
|
||||
|
||||
void Enumeration::setEnums(const char **plEnums)
|
||||
void Enumeration::setEnums(const char** plEnums)
|
||||
{
|
||||
std::string oldValue;
|
||||
bool preserve = (isValid() && plEnums != nullptr);
|
||||
if (preserve) {
|
||||
const char* str = getCStr();
|
||||
if (str)
|
||||
if (str) {
|
||||
oldValue = str;
|
||||
}
|
||||
}
|
||||
|
||||
enumArray.clear();
|
||||
@@ -118,14 +129,15 @@ void Enumeration::setEnums(const char **plEnums)
|
||||
}
|
||||
|
||||
// set _index
|
||||
if (_index < 0)
|
||||
if (_index < 0) {
|
||||
_index = 0;
|
||||
}
|
||||
if (preserve) {
|
||||
setValue(oldValue);
|
||||
}
|
||||
}
|
||||
|
||||
void Enumeration::setEnums(const std::vector<std::string> &values)
|
||||
void Enumeration::setEnums(const std::vector<std::string>& values)
|
||||
{
|
||||
if (values.empty()) {
|
||||
setEnums(nullptr);
|
||||
@@ -136,24 +148,26 @@ void Enumeration::setEnums(const std::vector<std::string> &values)
|
||||
bool preserve = isValid();
|
||||
if (preserve) {
|
||||
const char* str = getCStr();
|
||||
if (str)
|
||||
if (str) {
|
||||
oldValue = str;
|
||||
}
|
||||
}
|
||||
|
||||
enumArray.clear();
|
||||
for (const auto & it : values) {
|
||||
for (const auto& it : values) {
|
||||
enumArray.push_back(std::make_shared<StringCopy>(it.c_str()));
|
||||
}
|
||||
|
||||
// set _index
|
||||
if (_index < 0)
|
||||
if (_index < 0) {
|
||||
_index = 0;
|
||||
}
|
||||
if (preserve) {
|
||||
setValue(oldValue);
|
||||
}
|
||||
}
|
||||
|
||||
void Enumeration::setValue(const char *value)
|
||||
void Enumeration::setValue(const char* value)
|
||||
{
|
||||
_index = 0;
|
||||
for (std::size_t i = 0; i < enumArray.size(); i++) {
|
||||
@@ -168,41 +182,45 @@ void Enumeration::setValue(long value, bool checkRange)
|
||||
{
|
||||
if (value >= 0 && value < countItems()) {
|
||||
_index = value;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (checkRange) {
|
||||
throw Base::ValueError("Out of range");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
_index = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Enumeration::isValue(const char *value) const
|
||||
bool Enumeration::isValue(const char* value) const
|
||||
{
|
||||
int i = getInt();
|
||||
|
||||
if (i == -1) {
|
||||
return false;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return enumArray[i]->isEqual(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool Enumeration::contains(const char *value) const
|
||||
bool Enumeration::contains(const char* value) const
|
||||
{
|
||||
if (!isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& it : enumArray) {
|
||||
if (it->isEqual(value))
|
||||
if (it->isEqual(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char * Enumeration::getCStr() const
|
||||
const char* Enumeration::getCStr() const
|
||||
{
|
||||
if (!isValid() || _index < 0 || _index >= countItems()) {
|
||||
return nullptr;
|
||||
@@ -223,8 +241,9 @@ int Enumeration::getInt() const
|
||||
std::vector<std::string> Enumeration::getEnumVector() const
|
||||
{
|
||||
std::vector<std::string> list;
|
||||
for (const auto& it : enumArray)
|
||||
for (const auto& it : enumArray) {
|
||||
list.emplace_back(it->data());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -241,24 +260,27 @@ bool Enumeration::isValid() const
|
||||
int Enumeration::maxValue() const
|
||||
{
|
||||
int num = -1;
|
||||
if (!enumArray.empty())
|
||||
if (!enumArray.empty()) {
|
||||
num = static_cast<int>(enumArray.size()) - 1;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
bool Enumeration::isCustom() const
|
||||
{
|
||||
for (const auto& it : enumArray) {
|
||||
if (it->isCustom())
|
||||
if (it->isCustom()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Enumeration & Enumeration::operator=(const Enumeration &other)
|
||||
Enumeration& Enumeration::operator=(const Enumeration& other)
|
||||
{
|
||||
if (this == &other)
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
enumArray = other.enumArray;
|
||||
_index = other._index;
|
||||
@@ -266,23 +288,26 @@ Enumeration & Enumeration::operator=(const Enumeration &other)
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Enumeration::operator==(const Enumeration &other) const
|
||||
bool Enumeration::operator==(const Enumeration& other) const
|
||||
{
|
||||
if (_index != other._index || enumArray.size() != other.enumArray.size()) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < enumArray.size(); ++i) {
|
||||
if (enumArray[i]->data() == other.enumArray[i]->data())
|
||||
if (enumArray[i]->data() == other.enumArray[i]->data()) {
|
||||
continue;
|
||||
if (!enumArray[i]->data() || !other.enumArray[i]->data())
|
||||
}
|
||||
if (!enumArray[i]->data() || !other.enumArray[i]->data()) {
|
||||
return false;
|
||||
if (!enumArray[i]->isEqual(other.enumArray[i]->data()))
|
||||
}
|
||||
if (!enumArray[i]->isEqual(other.enumArray[i]->data())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Enumeration::operator==(const char *other) const
|
||||
bool Enumeration::operator==(const char* other) const
|
||||
{
|
||||
if (!getCStr()) {
|
||||
return false;
|
||||
|
||||
@@ -31,162 +31,166 @@
|
||||
|
||||
namespace App
|
||||
{
|
||||
/// A bidirectional string-integer mapping
|
||||
/*!
|
||||
* This is mainly intended for two purposes: working around the difficulty
|
||||
* in C++ of sharing enumerations between different source files,
|
||||
* namespaces, etc. and as the data type stored by App::PropertyEnumeration
|
||||
*
|
||||
* Internally, Enumeration maintains
|
||||
* -# Either a const pointer to an array of C-style strings, or a vector
|
||||
* of C++ std::strings
|
||||
* -# An integer index into that array/vector representing the string
|
||||
* representing the instance's value.
|
||||
*
|
||||
* If built with FC_DEBUG defined, some boundaries of passed in pointers
|
||||
* will be checked. Otherwise, the caller has the responsibility of
|
||||
* checking the limits of given indices.
|
||||
*
|
||||
* \todo Implement lazy copy
|
||||
*/
|
||||
class AppExport Enumeration
|
||||
/// A bidirectional string-integer mapping
|
||||
/*!
|
||||
* This is mainly intended for two purposes: working around the difficulty
|
||||
* in C++ of sharing enumerations between different source files,
|
||||
* namespaces, etc. and as the data type stored by App::PropertyEnumeration
|
||||
*
|
||||
* Internally, Enumeration maintains
|
||||
* -# Either a const pointer to an array of C-style strings, or a vector
|
||||
* of C++ std::strings
|
||||
* -# An integer index into that array/vector representing the string
|
||||
* representing the instance's value.
|
||||
*
|
||||
* If built with FC_DEBUG defined, some boundaries of passed in pointers
|
||||
* will be checked. Otherwise, the caller has the responsibility of
|
||||
* checking the limits of given indices.
|
||||
*
|
||||
* \todo Implement lazy copy
|
||||
*/
|
||||
class AppExport Enumeration
|
||||
{
|
||||
public:
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
class Object {
|
||||
public:
|
||||
virtual ~Object() = default;
|
||||
virtual const char* data() const = 0;
|
||||
virtual bool isEqual(const char*) const = 0;
|
||||
virtual bool isCustom() const = 0;
|
||||
};
|
||||
virtual ~Object() = default;
|
||||
virtual const char* data() const = 0;
|
||||
virtual bool isEqual(const char*) const = 0;
|
||||
virtual bool isCustom() const = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
/// Constructs an empty Enumeration object
|
||||
Enumeration();
|
||||
public:
|
||||
/// Constructs an empty Enumeration object
|
||||
Enumeration();
|
||||
|
||||
/// Standard copy constructor
|
||||
Enumeration(const Enumeration& other);
|
||||
/// Standard copy constructor
|
||||
Enumeration(const Enumeration& other);
|
||||
|
||||
/// Constructs an Enumeration with a single element
|
||||
explicit Enumeration(const char *valStr);
|
||||
/// Constructs an Enumeration with a single element
|
||||
explicit Enumeration(const char* valStr);
|
||||
|
||||
/// Constructs an Enumeration using val within list
|
||||
Enumeration(const char **list, const char *valStr);
|
||||
/// Constructs an Enumeration using val within list
|
||||
Enumeration(const char** list, const char* valStr);
|
||||
|
||||
/// Standard destructor
|
||||
~Enumeration();
|
||||
/// Standard destructor
|
||||
~Enumeration();
|
||||
|
||||
/** Sets the enumeration string list
|
||||
* The list is a NULL terminated array of pointers to const
|
||||
* char* strings.
|
||||
* \code
|
||||
* const char enums[] = {"Black","White","Other",NULL}
|
||||
* \endcode
|
||||
*
|
||||
* If Enumeration was already valid, will attempt to preserve
|
||||
* the string-representation value of the Enumeration
|
||||
*
|
||||
* Enumeration does not take ownership of the passed object
|
||||
*/
|
||||
void setEnums(const char **plEnums);
|
||||
/** Sets the enumeration string list
|
||||
* The list is a NULL terminated array of pointers to const
|
||||
* char* strings.
|
||||
* \code
|
||||
* const char enums[] = {"Black","White","Other",NULL}
|
||||
* \endcode
|
||||
*
|
||||
* If Enumeration was already valid, will attempt to preserve
|
||||
* the string-representation value of the Enumeration
|
||||
*
|
||||
* Enumeration does not take ownership of the passed object
|
||||
*/
|
||||
void setEnums(const char** plEnums);
|
||||
|
||||
/// Set all enum values as vector of strings
|
||||
/*!
|
||||
* This method causes the Enumeration to dynamically allocate
|
||||
* it's own array of C Strings, which will be deleted by the
|
||||
* destructor or subsequent calls to setEnums(). So, it is
|
||||
* important to make sure the Enumeration stays in scope as
|
||||
* long as values returned by getCStr are in use.
|
||||
*
|
||||
* If Enumeration was already valid, will attempt to preserve
|
||||
* the string-representation value of the Enumeration
|
||||
*/
|
||||
void setEnums(const std::vector<std::string> &values);
|
||||
/// Set all enum values as vector of strings
|
||||
/*!
|
||||
* This method causes the Enumeration to dynamically allocate
|
||||
* it's own array of C Strings, which will be deleted by the
|
||||
* destructor or subsequent calls to setEnums(). So, it is
|
||||
* important to make sure the Enumeration stays in scope as
|
||||
* long as values returned by getCStr are in use.
|
||||
*
|
||||
* If Enumeration was already valid, will attempt to preserve
|
||||
* the string-representation value of the Enumeration
|
||||
*/
|
||||
void setEnums(const std::vector<std::string>& values);
|
||||
|
||||
/// Set the enum using a C string
|
||||
void setValue(const char *value);
|
||||
/// Set the enum using a C string
|
||||
void setValue(const char* value);
|
||||
|
||||
/// Overload of setValue(const char *value)
|
||||
void setValue(const std::string &value) {setValue(value.c_str());}
|
||||
/// Overload of setValue(const char *value)
|
||||
void setValue(const std::string& value)
|
||||
{
|
||||
setValue(value.c_str());
|
||||
}
|
||||
|
||||
/// Set the enum using a long
|
||||
/*!
|
||||
* if checkRange is set to true, throws Base::ValueError when
|
||||
* values are set out of range
|
||||
*
|
||||
* Checks for boundaries via assert()
|
||||
*/
|
||||
void setValue(long value, bool checkRange = false);
|
||||
/// Set the enum using a long
|
||||
/*!
|
||||
* if checkRange is set to true, throws Base::ValueError when
|
||||
* values are set out of range
|
||||
*
|
||||
* Checks for boundaries via assert()
|
||||
*/
|
||||
void setValue(long value, bool checkRange = false);
|
||||
|
||||
/// Checks if the property is set to a certain string value
|
||||
bool isValue(const char *value) const;
|
||||
/// Checks if the property is set to a certain string value
|
||||
bool isValue(const char* value) const;
|
||||
|
||||
/// Checks if a string is included in the enumeration
|
||||
bool contains(const char *value) const;
|
||||
/// Checks if a string is included in the enumeration
|
||||
bool contains(const char* value) const;
|
||||
|
||||
/// Return the value as C string
|
||||
/*!
|
||||
* Returns NULL if the enumeration is invalid.
|
||||
*/
|
||||
const char * getCStr() const;
|
||||
/// Return the value as C string
|
||||
/*!
|
||||
* Returns NULL if the enumeration is invalid.
|
||||
*/
|
||||
const char* getCStr() const;
|
||||
|
||||
/// Return value as integer
|
||||
/*!
|
||||
* Returns -1 if the Enumeration isn't valid
|
||||
*/
|
||||
int getInt() const;
|
||||
/// Return value as integer
|
||||
/*!
|
||||
* Returns -1 if the Enumeration isn't valid
|
||||
*/
|
||||
int getInt() const;
|
||||
|
||||
/// get all possible enum values as vector of strings
|
||||
std::vector<std::string> getEnumVector() const;
|
||||
/// get all possible enum values as vector of strings
|
||||
std::vector<std::string> getEnumVector() const;
|
||||
|
||||
/// returns true if the enum list is non-empty, false otherwise
|
||||
bool hasEnums() const;
|
||||
/// returns true if the enum list is non-empty, false otherwise
|
||||
bool hasEnums() const;
|
||||
|
||||
/// Returns true if the instance is in a usable state
|
||||
bool isValid() const;
|
||||
/// Returns true if the instance is in a usable state
|
||||
bool isValid() const;
|
||||
|
||||
/// Returns the highest usable integer value for this enum
|
||||
/*!
|
||||
* Returns -1 if the enumeration is not valid according to isValid()
|
||||
*/
|
||||
int maxValue() const;
|
||||
/// Returns the highest usable integer value for this enum
|
||||
/*!
|
||||
* Returns -1 if the enumeration is not valid according to isValid()
|
||||
*/
|
||||
int maxValue() const;
|
||||
|
||||
/// Returns true if any of the items is a user-defined string
|
||||
bool isCustom() const;
|
||||
/// Returns true if any of the items is a user-defined string
|
||||
bool isCustom() const;
|
||||
|
||||
/// Assignment operator
|
||||
Enumeration & operator=(const Enumeration &other);
|
||||
/// Assignment operator
|
||||
Enumeration& operator=(const Enumeration& other);
|
||||
|
||||
/// true iff our string representation matches other's
|
||||
/*!
|
||||
* Returns false if either Enumeration is not valid.
|
||||
*/
|
||||
bool operator==(const Enumeration &other) const;
|
||||
/// true iff our string representation matches other's
|
||||
/*!
|
||||
* Returns false if either Enumeration is not valid.
|
||||
*/
|
||||
bool operator==(const Enumeration& other) const;
|
||||
|
||||
/// true iff our string representation matches other
|
||||
/*!
|
||||
* Returns false if Enumeration is not valid.
|
||||
*/
|
||||
bool operator==(const char *other) const;
|
||||
protected:
|
||||
/// true iff our string representation matches other
|
||||
/*!
|
||||
* Returns false if Enumeration is not valid.
|
||||
*/
|
||||
bool operator==(const char* other) const;
|
||||
|
||||
/// Number of items
|
||||
int countItems() const;
|
||||
protected:
|
||||
/// Number of items
|
||||
int countItems() const;
|
||||
|
||||
private:
|
||||
/// Handle to C Strings of possible enumeration values
|
||||
using ObjectPtr = std::shared_ptr<Object>;
|
||||
std::vector<ObjectPtr> enumArray;
|
||||
private:
|
||||
/// Handle to C Strings of possible enumeration values
|
||||
using ObjectPtr = std::shared_ptr<Object>;
|
||||
std::vector<ObjectPtr> enumArray;
|
||||
|
||||
/// Integer value of the enumeration
|
||||
/*!
|
||||
* This serves as an index into enumArray to get the string
|
||||
* representation.
|
||||
*/
|
||||
int _index;
|
||||
/// Integer value of the enumeration
|
||||
/*!
|
||||
* This serves as an index into enumArray to get the string
|
||||
* representation.
|
||||
*/
|
||||
int _index;
|
||||
|
||||
friend class PropertyEnumeration;
|
||||
}; // class Enumeration
|
||||
} // namespace App
|
||||
friend class PropertyEnumeration;
|
||||
}; // class Enumeration
|
||||
} // namespace App
|
||||
|
||||
#endif // #ifndef BASE_ENUMERATION_H
|
||||
#endif // #ifndef BASE_ENUMERATION_H
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <cassert>
|
||||
#include <cassert>
|
||||
#endif
|
||||
|
||||
#include <Base/PyObjectBase.h>
|
||||
@@ -39,167 +39,201 @@
|
||||
* PropertyData in the extension chain, there is no parent property data.
|
||||
*/
|
||||
EXTENSION_TYPESYSTEM_SOURCE_P(App::Extension)
|
||||
const App::PropertyData * App::Extension::extensionGetPropertyDataPtr(){return &propertyData;}
|
||||
const App::PropertyData & App::Extension::extensionGetPropertyData() const{return propertyData;}
|
||||
const App::PropertyData* App::Extension::extensionGetPropertyDataPtr()
|
||||
{
|
||||
return &propertyData;
|
||||
}
|
||||
const App::PropertyData& App::Extension::extensionGetPropertyData() const
|
||||
{
|
||||
return propertyData;
|
||||
}
|
||||
App::PropertyData App::Extension::propertyData;
|
||||
void App::Extension::init(){
|
||||
void App::Extension::init()
|
||||
{
|
||||
|
||||
assert(Extension::classTypeId == Base::Type::badType() && "don't init() twice!");
|
||||
|
||||
/* Set up entry in the type system. */
|
||||
Extension::classTypeId = Base::Type::createType(Base::Type::badType(), "App::Extension",
|
||||
Extension::create);
|
||||
Extension::classTypeId =
|
||||
Base::Type::createType(Base::Type::badType(), "App::Extension", Extension::create);
|
||||
}
|
||||
|
||||
using namespace App;
|
||||
|
||||
Extension::~Extension()
|
||||
{
|
||||
if (!ExtensionPythonObject.is(Py::_None())){
|
||||
if (!ExtensionPythonObject.is(Py::_None())) {
|
||||
// Remark: The API of Py::Object has been changed to set whether the wrapper owns the passed
|
||||
// Python object or not. In the constructor we forced the wrapper to own the object so we need
|
||||
// not to dec'ref the Python object any more.
|
||||
// But we must still invalidate the Python object because it need not to be
|
||||
// destructed right now because the interpreter can own several references to it.
|
||||
// Python object or not. In the constructor we forced the wrapper to own the object so we
|
||||
// need not to dec'ref the Python object any more. But we must still invalidate the Python
|
||||
// object because it need not to be destructed right now because the interpreter can own
|
||||
// several references to it.
|
||||
Base::PyObjectBase* obj = static_cast<Base::PyObjectBase*>(ExtensionPythonObject.ptr());
|
||||
// Call before decrementing the reference counter, otherwise a heap error can occur
|
||||
obj->setInvalid();
|
||||
}
|
||||
}
|
||||
|
||||
void Extension::initExtensionType(Base::Type type) {
|
||||
void Extension::initExtensionType(Base::Type type)
|
||||
{
|
||||
|
||||
m_extensionType = type;
|
||||
if (m_extensionType.isBad())
|
||||
if (m_extensionType.isBad()) {
|
||||
throw Base::RuntimeError("Extension: Extension type not set");
|
||||
}
|
||||
}
|
||||
|
||||
void Extension::initExtension(ExtensionContainer* obj) {
|
||||
if (m_extensionType.isBad())
|
||||
void Extension::initExtension(ExtensionContainer* obj)
|
||||
{
|
||||
if (m_extensionType.isBad()) {
|
||||
throw Base::RuntimeError("Extension: Extension type not set");
|
||||
}
|
||||
|
||||
//all properties are initialised without PropertyContainer father. Now that we know it we can
|
||||
//finally finish the property initialisation
|
||||
// all properties are initialised without PropertyContainer father. Now that we know it we can
|
||||
// finally finish the property initialisation
|
||||
std::vector<Property*> list;
|
||||
extensionGetPropertyData().getPropertyList(this, list);
|
||||
for(Property* prop : list)
|
||||
for (Property* prop : list) {
|
||||
prop->setContainer(obj);
|
||||
}
|
||||
|
||||
m_base = obj;
|
||||
m_base->registerExtension( m_extensionType, this );
|
||||
m_base->registerExtension(m_extensionType, this);
|
||||
}
|
||||
|
||||
|
||||
PyObject* Extension::getExtensionPyObject() {
|
||||
PyObject* Extension::getExtensionPyObject()
|
||||
{
|
||||
|
||||
if (ExtensionPythonObject.is(Py::_None())){
|
||||
if (ExtensionPythonObject.is(Py::_None())) {
|
||||
// ref counter is set to 1
|
||||
auto grp = new ExtensionPy(this);
|
||||
ExtensionPythonObject = Py::Object(grp,true);
|
||||
ExtensionPythonObject = Py::Object(grp, true);
|
||||
}
|
||||
return Py::new_reference_to(ExtensionPythonObject);
|
||||
}
|
||||
|
||||
std::string Extension::name() const {
|
||||
std::string Extension::name() const
|
||||
{
|
||||
|
||||
if (m_extensionType.isBad())
|
||||
if (m_extensionType.isBad()) {
|
||||
throw Base::RuntimeError("Extension::name: Extension type not set");
|
||||
}
|
||||
|
||||
std::string temp(m_extensionType.getName());
|
||||
std::string::size_type pos = temp.find_last_of(':');
|
||||
|
||||
if (pos != std::string::npos)
|
||||
return temp.substr(pos+1);
|
||||
if (pos != std::string::npos) {
|
||||
return temp.substr(pos + 1);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Property* Extension::extensionGetPropertyByName(const char* name) const {
|
||||
Property* Extension::extensionGetPropertyByName(const char* name) const
|
||||
{
|
||||
|
||||
return extensionGetPropertyData().getPropertyByName(this, name);
|
||||
}
|
||||
|
||||
short int Extension::extensionGetPropertyType(const Property* prop) const {
|
||||
short int Extension::extensionGetPropertyType(const Property* prop) const
|
||||
{
|
||||
|
||||
return extensionGetPropertyData().getType(this, prop);
|
||||
}
|
||||
|
||||
short int Extension::extensionGetPropertyType(const char* name) const {
|
||||
short int Extension::extensionGetPropertyType(const char* name) const
|
||||
{
|
||||
|
||||
return extensionGetPropertyData().getType(this, name);
|
||||
}
|
||||
|
||||
const char* Extension::extensionGetPropertyName(const Property* prop) const {
|
||||
const char* Extension::extensionGetPropertyName(const Property* prop) const
|
||||
{
|
||||
|
||||
return extensionGetPropertyData().getName(this,prop);
|
||||
return extensionGetPropertyData().getName(this, prop);
|
||||
}
|
||||
|
||||
const char* Extension::extensionGetPropertyGroup(const Property* prop) const {
|
||||
const char* Extension::extensionGetPropertyGroup(const Property* prop) const
|
||||
{
|
||||
|
||||
return extensionGetPropertyData().getGroup(this,prop);
|
||||
return extensionGetPropertyData().getGroup(this, prop);
|
||||
}
|
||||
|
||||
const char* Extension::extensionGetPropertyGroup(const char* name) const {
|
||||
const char* Extension::extensionGetPropertyGroup(const char* name) const
|
||||
{
|
||||
|
||||
return extensionGetPropertyData().getGroup(this,name);
|
||||
return extensionGetPropertyData().getGroup(this, name);
|
||||
}
|
||||
|
||||
|
||||
const char* Extension::extensionGetPropertyDocumentation(const Property* prop) const {
|
||||
const char* Extension::extensionGetPropertyDocumentation(const Property* prop) const
|
||||
{
|
||||
|
||||
return extensionGetPropertyData().getDocumentation(this, prop);
|
||||
}
|
||||
|
||||
const char* Extension::extensionGetPropertyDocumentation(const char* name) const {
|
||||
const char* Extension::extensionGetPropertyDocumentation(const char* name) const
|
||||
{
|
||||
|
||||
return extensionGetPropertyData().getDocumentation(this, name);
|
||||
}
|
||||
|
||||
void Extension::extensionGetPropertyList(std::vector< Property* >& List) const {
|
||||
void Extension::extensionGetPropertyList(std::vector<Property*>& List) const
|
||||
{
|
||||
|
||||
extensionGetPropertyData().getPropertyList(this, List);
|
||||
}
|
||||
|
||||
void Extension::extensionGetPropertyMap(std::map< std::string, Property* >& Map) const {
|
||||
void Extension::extensionGetPropertyMap(std::map<std::string, Property*>& Map) const
|
||||
{
|
||||
|
||||
extensionGetPropertyData().getPropertyMap(this, Map);
|
||||
}
|
||||
|
||||
void Extension::initExtensionSubclass(Base::Type& toInit, const char* ClassName, const char* ParentName,
|
||||
Base::Type::instantiationMethod method) {
|
||||
void Extension::initExtensionSubclass(Base::Type& toInit,
|
||||
const char* ClassName,
|
||||
const char* ParentName,
|
||||
Base::Type::instantiationMethod method)
|
||||
{
|
||||
|
||||
// don't init twice!
|
||||
assert(toInit == Base::Type::badType());
|
||||
// get the parent class
|
||||
Base::Type parentType(Base::Type::fromName(ParentName));
|
||||
// forgot init parent!
|
||||
assert(parentType != Base::Type::badType() );
|
||||
assert(parentType != Base::Type::badType());
|
||||
|
||||
// create the new type
|
||||
toInit = Base::Type::createType(parentType, ClassName, method);
|
||||
}
|
||||
|
||||
|
||||
bool Extension::extensionHandleChangedPropertyName(Base::XMLReader &reader, const char * TypeName, const char *PropName)
|
||||
bool Extension::extensionHandleChangedPropertyName(Base::XMLReader& reader,
|
||||
const char* TypeName,
|
||||
const char* PropName)
|
||||
{
|
||||
(void) reader;
|
||||
(void) TypeName;
|
||||
(void) PropName;
|
||||
(void)reader;
|
||||
(void)TypeName;
|
||||
(void)PropName;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
bool Extension::extensionHandleChangedPropertyType(Base::XMLReader &reader, const char * TypeName, Property * prop)
|
||||
bool Extension::extensionHandleChangedPropertyType(Base::XMLReader& reader,
|
||||
const char* TypeName,
|
||||
Property* prop)
|
||||
{
|
||||
(void) reader;
|
||||
(void) TypeName;
|
||||
(void) prop;
|
||||
(void)reader;
|
||||
(void)TypeName;
|
||||
(void)prop;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
EXTENSION_PROPERTY_SOURCE_TEMPLATE(App::ExtensionPython, App::ExtensionPython::Inherited)
|
||||
|
||||
// explicit template instantiation
|
||||
template class AppExport ExtensionPythonT<Extension>;
|
||||
}
|
||||
} // namespace App
|
||||
|
||||
@@ -38,23 +38,28 @@ TYPESYSTEM_SOURCE(App::ExtensionContainer, App::PropertyContainer)
|
||||
|
||||
ExtensionContainer::ExtensionContainer() = default;
|
||||
|
||||
ExtensionContainer::~ExtensionContainer() {
|
||||
ExtensionContainer::~ExtensionContainer()
|
||||
{
|
||||
|
||||
//we need to delete all dynamically added extensions
|
||||
for(const auto& entry : _extensions) {
|
||||
if(entry.second->isPythonExtension())
|
||||
// we need to delete all dynamically added extensions
|
||||
for (const auto& entry : _extensions) {
|
||||
if (entry.second->isPythonExtension()) {
|
||||
delete entry.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExtensionContainer::registerExtension(Base::Type extension, Extension* ext) {
|
||||
if(ext->getExtendedContainer() != this)
|
||||
throw Base::ValueError("ExtensionContainer::registerExtension: Extension has not this as base object");
|
||||
void ExtensionContainer::registerExtension(Base::Type extension, Extension* ext)
|
||||
{
|
||||
if (ext->getExtendedContainer() != this) {
|
||||
throw Base::ValueError(
|
||||
"ExtensionContainer::registerExtension: Extension has not this as base object");
|
||||
}
|
||||
|
||||
//no duplicate extensions (including base classes)
|
||||
if(hasExtension(extension)) {
|
||||
for(const auto& entry : _extensions) {
|
||||
if(entry.first == extension || entry.first.isDerivedFrom(extension)) {
|
||||
// no duplicate extensions (including base classes)
|
||||
if (hasExtension(extension)) {
|
||||
for (const auto& entry : _extensions) {
|
||||
if (entry.first == extension || entry.first.isDerivedFrom(extension)) {
|
||||
_extensions.erase(entry.first);
|
||||
break;
|
||||
}
|
||||
@@ -64,275 +69,325 @@ void ExtensionContainer::registerExtension(Base::Type extension, Extension* ext)
|
||||
_extensions[extension] = ext;
|
||||
}
|
||||
|
||||
bool ExtensionContainer::hasExtension(Base::Type t, bool derived) const {
|
||||
bool ExtensionContainer::hasExtension(Base::Type t, bool derived) const
|
||||
{
|
||||
|
||||
//check for the exact type
|
||||
// check for the exact type
|
||||
bool found = _extensions.find(t) != _extensions.end();
|
||||
if(!found && derived) {
|
||||
//and for types derived from it, as they can be cast to the extension
|
||||
for(const auto& entry : _extensions) {
|
||||
if(entry.first.isDerivedFrom(t))
|
||||
if (!found && derived) {
|
||||
// and for types derived from it, as they can be cast to the extension
|
||||
for (const auto& entry : _extensions) {
|
||||
if (entry.first.isDerivedFrom(t)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
bool ExtensionContainer::hasExtension(const std::string& name) const {
|
||||
bool ExtensionContainer::hasExtension(const std::string& name) const
|
||||
{
|
||||
|
||||
//and for types derived from it, as they can be cast to the extension
|
||||
for(const auto& entry : _extensions) {
|
||||
if(entry.second->name() == name)
|
||||
// and for types derived from it, as they can be cast to the extension
|
||||
for (const auto& entry : _extensions) {
|
||||
if (entry.second->name() == name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Extension* ExtensionContainer::getExtension(Base::Type t, bool derived, bool no_except) const {
|
||||
Extension* ExtensionContainer::getExtension(Base::Type t, bool derived, bool no_except) const
|
||||
{
|
||||
|
||||
auto result = _extensions.find(t);
|
||||
if((result == _extensions.end()) && derived) {
|
||||
//we need to check for derived types
|
||||
for(const auto& entry : _extensions) {
|
||||
if(entry.first.isDerivedFrom(t))
|
||||
if ((result == _extensions.end()) && derived) {
|
||||
// we need to check for derived types
|
||||
for (const auto& entry : _extensions) {
|
||||
if (entry.first.isDerivedFrom(t)) {
|
||||
return entry.second;
|
||||
}
|
||||
}
|
||||
if(no_except)
|
||||
if (no_except) {
|
||||
return nullptr;
|
||||
//if we arrive here we don't have anything matching
|
||||
throw Base::TypeError("ExtensionContainer::getExtension: No extension of given type available");
|
||||
}
|
||||
// if we arrive here we don't have anything matching
|
||||
throw Base::TypeError(
|
||||
"ExtensionContainer::getExtension: No extension of given type available");
|
||||
}
|
||||
else if (result != _extensions.end()) {
|
||||
return result->second;
|
||||
}
|
||||
else {
|
||||
if(no_except)
|
||||
if (no_except) {
|
||||
return nullptr;
|
||||
//if we arrive here we don't have anything matching
|
||||
throw Base::TypeError("ExtensionContainer::getExtension: No extension of given type available");
|
||||
}
|
||||
// if we arrive here we don't have anything matching
|
||||
throw Base::TypeError(
|
||||
"ExtensionContainer::getExtension: No extension of given type available");
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtensionContainer::hasExtensions() const {
|
||||
bool ExtensionContainer::hasExtensions() const
|
||||
{
|
||||
|
||||
return !_extensions.empty();
|
||||
}
|
||||
|
||||
Extension* ExtensionContainer::getExtension(const std::string& name) const {
|
||||
Extension* ExtensionContainer::getExtension(const std::string& name) const
|
||||
{
|
||||
|
||||
//and for types derived from it, as they can be cast to the extension
|
||||
for(const auto& entry : _extensions) {
|
||||
if(entry.second->name() == name)
|
||||
// and for types derived from it, as they can be cast to the extension
|
||||
for (const auto& entry : _extensions) {
|
||||
if (entry.second->name() == name) {
|
||||
return entry.second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector< Extension* > ExtensionContainer::getExtensionsDerivedFrom(Base::Type type) const {
|
||||
std::vector<Extension*> ExtensionContainer::getExtensionsDerivedFrom(Base::Type type) const
|
||||
{
|
||||
|
||||
std::vector<Extension*> vec;
|
||||
//and for types derived from it, as they can be cast to the extension
|
||||
for(const auto& entry : _extensions) {
|
||||
if(entry.first.isDerivedFrom(type))
|
||||
// and for types derived from it, as they can be cast to the extension
|
||||
for (const auto& entry : _extensions) {
|
||||
if (entry.first.isDerivedFrom(type)) {
|
||||
vec.push_back(entry.second);
|
||||
}
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
void ExtensionContainer::getPropertyList(std::vector< Property* >& List) const {
|
||||
void ExtensionContainer::getPropertyList(std::vector<Property*>& List) const
|
||||
{
|
||||
App::PropertyContainer::getPropertyList(List);
|
||||
for(const auto& entry : _extensions)
|
||||
for (const auto& entry : _extensions) {
|
||||
entry.second->extensionGetPropertyList(List);
|
||||
}
|
||||
}
|
||||
|
||||
void ExtensionContainer::getPropertyMap(std::map< std::string, Property* >& Map) const {
|
||||
void ExtensionContainer::getPropertyMap(std::map<std::string, Property*>& Map) const
|
||||
{
|
||||
App::PropertyContainer::getPropertyMap(Map);
|
||||
for(const auto& entry : _extensions)
|
||||
for (const auto& entry : _extensions) {
|
||||
entry.second->extensionGetPropertyMap(Map);
|
||||
}
|
||||
}
|
||||
|
||||
Property* ExtensionContainer::getPropertyByName(const char* name) const {
|
||||
Property* ExtensionContainer::getPropertyByName(const char* name) const
|
||||
{
|
||||
auto prop = App::PropertyContainer::getPropertyByName(name);
|
||||
if(prop)
|
||||
if (prop) {
|
||||
return prop;
|
||||
}
|
||||
|
||||
for(const auto& entry : _extensions) {
|
||||
for (const auto& entry : _extensions) {
|
||||
auto prop = entry.second->extensionGetPropertyByName(name);
|
||||
if(prop)
|
||||
if (prop) {
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
short int ExtensionContainer::getPropertyType(const Property* prop) const {
|
||||
short int ExtensionContainer::getPropertyType(const Property* prop) const
|
||||
{
|
||||
short int res = App::PropertyContainer::getPropertyType(prop);
|
||||
if(res != 0)
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
for(const auto& entry : _extensions) {
|
||||
for (const auto& entry : _extensions) {
|
||||
res = entry.second->extensionGetPropertyType(prop);
|
||||
if(res != 0)
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
short int ExtensionContainer::getPropertyType(const char* name) const {
|
||||
short int ExtensionContainer::getPropertyType(const char* name) const
|
||||
{
|
||||
|
||||
short int res = App::PropertyContainer::getPropertyType(name);
|
||||
if(res != 0)
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
for(const auto& entry : _extensions) {
|
||||
for (const auto& entry : _extensions) {
|
||||
res = entry.second->extensionGetPropertyType(name);
|
||||
if(res != 0)
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const char* ExtensionContainer::getPropertyName(const Property* prop) const {
|
||||
const char* ExtensionContainer::getPropertyName(const Property* prop) const
|
||||
{
|
||||
|
||||
const char* res = App::PropertyContainer::getPropertyName(prop);
|
||||
if (res)
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
for (const auto& entry : _extensions) {
|
||||
res = entry.second->extensionGetPropertyName(prop);
|
||||
if (res)
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* ExtensionContainer::getPropertyGroup(const Property* prop) const {
|
||||
const char* ExtensionContainer::getPropertyGroup(const Property* prop) const
|
||||
{
|
||||
|
||||
const char* res = App::PropertyContainer::getPropertyGroup(prop);
|
||||
if (res)
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
for (const auto& entry : _extensions) {
|
||||
res = entry.second->extensionGetPropertyGroup(prop);
|
||||
if (res)
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* ExtensionContainer::getPropertyGroup(const char* name) const {
|
||||
const char* ExtensionContainer::getPropertyGroup(const char* name) const
|
||||
{
|
||||
|
||||
const char* res = App::PropertyContainer::getPropertyGroup(name);
|
||||
if (res)
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
for (const auto& entry : _extensions) {
|
||||
res = entry.second->extensionGetPropertyGroup(name);
|
||||
if (res)
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
const char* ExtensionContainer::getPropertyDocumentation(const Property* prop) const {
|
||||
const char* ExtensionContainer::getPropertyDocumentation(const Property* prop) const
|
||||
{
|
||||
|
||||
const char* res = App::PropertyContainer::getPropertyDocumentation(prop);
|
||||
if (res)
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
for (const auto& entry : _extensions) {
|
||||
res = entry.second->extensionGetPropertyDocumentation(prop);
|
||||
if (res)
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* ExtensionContainer::getPropertyDocumentation(const char* name) const {
|
||||
const char* ExtensionContainer::getPropertyDocumentation(const char* name) const
|
||||
{
|
||||
|
||||
const char* res = App::PropertyContainer::getPropertyDocumentation(name);
|
||||
if (res)
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
for(const auto& entry : _extensions) {
|
||||
for (const auto& entry : _extensions) {
|
||||
res = entry.second->extensionGetPropertyDocumentation(name);
|
||||
if (res)
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ExtensionContainer::onChanged(const Property* prop) {
|
||||
void ExtensionContainer::onChanged(const Property* prop)
|
||||
{
|
||||
|
||||
//inform all extensions about changed property. This includes all properties from the
|
||||
//extended object (this) as well as all extension properties
|
||||
for(const auto& entry : _extensions)
|
||||
// inform all extensions about changed property. This includes all properties from the
|
||||
// extended object (this) as well as all extension properties
|
||||
for (const auto& entry : _extensions) {
|
||||
entry.second->extensionOnChanged(prop);
|
||||
}
|
||||
|
||||
App::PropertyContainer::onChanged(prop);
|
||||
}
|
||||
|
||||
void ExtensionContainer::Save(Base::Writer& writer) const {
|
||||
void ExtensionContainer::Save(Base::Writer& writer) const
|
||||
{
|
||||
|
||||
//Note: save extensions must be called first to ensure that the extension element is always the
|
||||
// very first inside the object element. This is needed since extension element works together with
|
||||
// an object attribute, and if another element would be read first the object attributes would be
|
||||
// cleared.
|
||||
// Note: save extensions must be called first to ensure that the extension element is always the
|
||||
// very first inside the object element. This is needed since extension element works
|
||||
// together with an object attribute, and if another element would be read first the
|
||||
// object attributes would be cleared.
|
||||
saveExtensions(writer);
|
||||
App::PropertyContainer::Save(writer);
|
||||
}
|
||||
|
||||
void ExtensionContainer::Restore(Base::XMLReader& reader) {
|
||||
void ExtensionContainer::Restore(Base::XMLReader& reader)
|
||||
{
|
||||
|
||||
//restore dynamic extensions.
|
||||
//Note 1: The extension element must be read first, before all other object elements. That is
|
||||
// needed as the element works together with an object element attribute, which would be
|
||||
// cleared if another attribute is read first
|
||||
//Note 2: This must happen before the py object of this container is used, as only in the
|
||||
// pyobject constructor the extension methods are added to the container.
|
||||
// restore dynamic extensions.
|
||||
// Note 1: The extension element must be read first, before all other object elements. That is
|
||||
// needed as the element works together with an object element attribute, which would be
|
||||
// cleared if another attribute is read first
|
||||
// Note 2: This must happen before the py object of this container is used, as only in the
|
||||
// pyobject constructor the extension methods are added to the container.
|
||||
restoreExtensions(reader);
|
||||
App::PropertyContainer::Restore(reader);
|
||||
}
|
||||
|
||||
void ExtensionContainer::saveExtensions(Base::Writer& writer) const {
|
||||
void ExtensionContainer::saveExtensions(Base::Writer& writer) const
|
||||
{
|
||||
|
||||
//we don't save anything if there are no dynamic extensions
|
||||
if(!hasExtensions())
|
||||
// we don't save anything if there are no dynamic extensions
|
||||
if (!hasExtensions()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//save dynamic extensions
|
||||
writer.incInd(); // indentation for 'Extensions'
|
||||
writer.Stream() << writer.ind() << "<Extensions Count=\"" << _extensions.size() << "\">" << std::endl;
|
||||
for(const auto& entry : _extensions) {
|
||||
// save dynamic extensions
|
||||
writer.incInd(); // indentation for 'Extensions'
|
||||
writer.Stream() << writer.ind() << "<Extensions Count=\"" << _extensions.size() << "\">"
|
||||
<< std::endl;
|
||||
for (const auto& entry : _extensions) {
|
||||
|
||||
auto ext = entry.second;
|
||||
writer.incInd(); // indentation for 'Extension name'
|
||||
writer.incInd(); // indentation for 'Extension name'
|
||||
writer.Stream() << writer.ind() << "<Extension"
|
||||
<< " type=\"" << ext->getExtensionTypeId().getName() <<"\""
|
||||
<< " name=\"" << ext->name() << "\">" << std::endl;
|
||||
writer.incInd(); // indentation for the actual Extension
|
||||
<< " type=\"" << ext->getExtensionTypeId().getName() << "\""
|
||||
<< " name=\"" << ext->name() << "\">" << std::endl;
|
||||
writer.incInd(); // indentation for the actual Extension
|
||||
try {
|
||||
// We must make sure to handle all exceptions accordingly so that
|
||||
// the project file doesn't get invalidated. In the error case this
|
||||
// means to proceed instead of aborting the write operation.
|
||||
ext->extensionSave(writer);
|
||||
}
|
||||
catch (const Base::Exception &e) {
|
||||
catch (const Base::Exception& e) {
|
||||
Base::Console().Error("%s\n", e.what());
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
catch (const std::exception& e) {
|
||||
Base::Console().Error("%s\n", e.what());
|
||||
}
|
||||
catch (const char* e) {
|
||||
@@ -340,47 +395,51 @@ void ExtensionContainer::saveExtensions(Base::Writer& writer) const {
|
||||
}
|
||||
#ifndef FC_DEBUG
|
||||
catch (...) {
|
||||
Base::Console().Error("ExtensionContainer::Save: Unknown C++ exception thrown. Try to continue...\n");
|
||||
Base::Console().Error(
|
||||
"ExtensionContainer::Save: Unknown C++ exception thrown. Try to continue...\n");
|
||||
}
|
||||
#endif
|
||||
writer.decInd(); // indentation for the actual extension
|
||||
writer.decInd(); // indentation for the actual extension
|
||||
writer.Stream() << writer.ind() << "</Extension>" << std::endl;
|
||||
writer.decInd(); // indentation for 'Extension name'
|
||||
writer.decInd(); // indentation for 'Extension name'
|
||||
}
|
||||
writer.Stream() << writer.ind() << "</Extensions>" << std::endl;
|
||||
writer.decInd();
|
||||
}
|
||||
|
||||
void ExtensionContainer::restoreExtensions(Base::XMLReader& reader) {
|
||||
void ExtensionContainer::restoreExtensions(Base::XMLReader& reader)
|
||||
{
|
||||
|
||||
//Dynamic extensions are optional (also because they are introduced late into the document format)
|
||||
//and hence it is possible that the element does not exist. As we cannot check for the existence of
|
||||
//an element a object attribute is set if extensions are available. Here we check that
|
||||
//attribute, and only if it exists the extensions element will be available.
|
||||
if(!reader.hasAttribute("Extensions"))
|
||||
// Dynamic extensions are optional (also because they are introduced late into the document
|
||||
// format) and hence it is possible that the element does not exist. As we cannot check for the
|
||||
// existence of an element a object attribute is set if extensions are available. Here we check
|
||||
// that attribute, and only if it exists the extensions element will be available.
|
||||
if (!reader.hasAttribute("Extensions")) {
|
||||
return;
|
||||
}
|
||||
|
||||
reader.readElement("Extensions");
|
||||
int Cnt = reader.getAttributeAsInteger("Count");
|
||||
|
||||
for (int i=0 ;i<Cnt ;i++) {
|
||||
for (int i = 0; i < Cnt; i++) {
|
||||
reader.readElement("Extension");
|
||||
const char* Type = reader.getAttribute("type");
|
||||
const char* Name = reader.getAttribute("name");
|
||||
try {
|
||||
App::Extension* ext = getExtension(Name);
|
||||
if(!ext) {
|
||||
//get the extension type asked for
|
||||
Base::Type extension = Base::Type::fromName(Type);
|
||||
if (extension.isBad() || !extension.isDerivedFrom(App::Extension::getExtensionClassTypeId())) {
|
||||
if (!ext) {
|
||||
// get the extension type asked for
|
||||
Base::Type extension = Base::Type::fromName(Type);
|
||||
if (extension.isBad()
|
||||
|| !extension.isDerivedFrom(App::Extension::getExtensionClassTypeId())) {
|
||||
std::stringstream str;
|
||||
str << "No extension found of type '" << Type << "'" << std::ends;
|
||||
throw Base::TypeError(str.str());
|
||||
}
|
||||
|
||||
//register the extension
|
||||
// register the extension
|
||||
ext = static_cast<App::Extension*>(extension.createInstance());
|
||||
//check if this really is a python extension!
|
||||
// check if this really is a python extension!
|
||||
if (!ext->isPythonExtension()) {
|
||||
delete ext;
|
||||
std::stringstream str;
|
||||
@@ -390,16 +449,17 @@ void ExtensionContainer::restoreExtensions(Base::XMLReader& reader) {
|
||||
|
||||
ext->initExtension(this);
|
||||
}
|
||||
if (ext && strcmp(ext->getExtensionTypeId().getName(), Type) == 0)
|
||||
if (ext && strcmp(ext->getExtensionTypeId().getName(), Type) == 0) {
|
||||
ext->extensionRestore(reader);
|
||||
}
|
||||
}
|
||||
catch (const Base::XMLParseException&) {
|
||||
throw; // re-throw
|
||||
throw; // re-throw
|
||||
}
|
||||
catch (const Base::Exception &e) {
|
||||
catch (const Base::Exception& e) {
|
||||
Base::Console().Error("%s\n", e.what());
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
catch (const std::exception& e) {
|
||||
Base::Console().Error("%s\n", e.what());
|
||||
}
|
||||
catch (const char* e) {
|
||||
@@ -416,29 +476,35 @@ void ExtensionContainer::restoreExtensions(Base::XMLReader& reader) {
|
||||
reader.readEndElement("Extensions");
|
||||
}
|
||||
|
||||
void ExtensionContainer::handleChangedPropertyName(Base::XMLReader &reader, const char * TypeName, const char *PropName)
|
||||
void ExtensionContainer::handleChangedPropertyName(Base::XMLReader& reader,
|
||||
const char* TypeName,
|
||||
const char* PropName)
|
||||
{
|
||||
//inform all extensions about changed property name. This includes all properties from the
|
||||
//extended object (this) as well as all extension properties
|
||||
for(const auto& entry : _extensions) {
|
||||
// inform all extensions about changed property name. This includes all properties from the
|
||||
// extended object (this) as well as all extension properties
|
||||
for (const auto& entry : _extensions) {
|
||||
bool handled = entry.second->extensionHandleChangedPropertyName(reader, TypeName, PropName);
|
||||
|
||||
if(handled)
|
||||
return; // one property change needs only be handled once
|
||||
if (handled) {
|
||||
return; // one property change needs only be handled once
|
||||
}
|
||||
}
|
||||
|
||||
PropertyContainer::handleChangedPropertyName(reader, TypeName, PropName);
|
||||
}
|
||||
|
||||
void ExtensionContainer::handleChangedPropertyType(Base::XMLReader &reader, const char * TypeName, Property * prop)
|
||||
void ExtensionContainer::handleChangedPropertyType(Base::XMLReader& reader,
|
||||
const char* TypeName,
|
||||
Property* prop)
|
||||
{
|
||||
//inform all extensions about changed property type. This includes all properties from the
|
||||
//extended object (this) as well as all extension properties
|
||||
for(const auto& entry : _extensions) {
|
||||
// inform all extensions about changed property type. This includes all properties from the
|
||||
// extended object (this) as well as all extension properties
|
||||
for (const auto& entry : _extensions) {
|
||||
bool handled = entry.second->extensionHandleChangedPropertyType(reader, TypeName, prop);
|
||||
|
||||
if(handled)
|
||||
return; // one property change needs only be handled once
|
||||
if (handled) {
|
||||
return; // one property change needs only be handled once
|
||||
}
|
||||
}
|
||||
|
||||
PropertyContainer::handleChangedPropertyType(reader, TypeName, prop);
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
#include "PropertyContainer.h"
|
||||
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
|
||||
class Extension;
|
||||
/**
|
||||
@@ -49,14 +50,14 @@ class Extension;
|
||||
* - Extensions can be added from c++ and python, even from both together
|
||||
*
|
||||
* The interoperability with python is highly important, as in FreeCAD all functionality should be
|
||||
* as easily accessible from python as from c++. To ensure this, and as already noted, extensions can
|
||||
* be added to a object from python. However, this means that it is not clear from the c++ object type
|
||||
* if an extension was added or not. If added from c++ it becomes clear in the type due to the use of
|
||||
* multiple inheritance. If added from python it is a runtime extension and not visible from type.
|
||||
* Hence querying existing extensions of an object and accessing its methods works not by type
|
||||
* casting but by the interface provided in ExtensionContainer. The default workflow is to query if
|
||||
* an extension exists and then get the extension object. No matter if added from python or c++ this
|
||||
* interface works always the same.
|
||||
* as easily accessible from python as from c++. To ensure this, and as already noted, extensions
|
||||
* can be added to a object from python. However, this means that it is not clear from the c++
|
||||
* object type if an extension was added or not. If added from c++ it becomes clear in the type due
|
||||
* to the use of multiple inheritance. If added from python it is a runtime extension and not
|
||||
* visible from type. Hence querying existing extensions of an object and accessing its methods
|
||||
* works not by type casting but by the interface provided in ExtensionContainer. The default
|
||||
* workflow is to query if an extension exists and then get the extension object. No matter if added
|
||||
* from python or c++ this interface works always the same.
|
||||
* @code
|
||||
* if (object->hasExtension(GroupExtension::getClassTypeId())) {
|
||||
* App::GroupExtension* group = object->getExtensionByType<GroupExtension>();
|
||||
@@ -77,8 +78,8 @@ class Extension;
|
||||
*
|
||||
* Here is a working example:
|
||||
* @code
|
||||
* class AppExport Part : public App::DocumentObject, public App::FirstExtension, public App::SecondExtension {
|
||||
* PROPERTY_HEADER_WITH_EXTENSIONS(App::Part);
|
||||
* class AppExport Part : public App::DocumentObject, public App::FirstExtension, public
|
||||
* App::SecondExtension { PROPERTY_HEADER_WITH_EXTENSIONS(App::Part);
|
||||
* };
|
||||
* PROPERTY_SOURCE_WITH_EXTENSIONS(App::Part, App::DocumentObject)
|
||||
* Part::Part(void) {
|
||||
@@ -88,9 +89,9 @@ class Extension;
|
||||
* @endcode
|
||||
*
|
||||
* From python adding an extension is easier, it must be simply registered to a document object
|
||||
* at object initialisation like done with properties. Note that the special python extension objects
|
||||
* need to be added, not the c++ objects. Normally the only difference in name is the additional
|
||||
* "Python" at the end of the extension name.
|
||||
* at object initialisation like done with properties. Note that the special python extension
|
||||
* objects need to be added, not the c++ objects. Normally the only difference in name is the
|
||||
* additional "Python" at the end of the extension name.
|
||||
* @code{.py}
|
||||
* class Test():
|
||||
* __init(self)__:
|
||||
@@ -99,86 +100,98 @@ class Extension;
|
||||
* @endcode
|
||||
*
|
||||
* Extensions can provide methods that should be overridden by the extended object for customisation
|
||||
* of the extension behaviour. In c++ this is as simple as overriding the provided virtual functions.
|
||||
* In python a class method must be provided which has the same name as the method to override. This
|
||||
* method must not necessarily be in the object that is extended, it must be in the object which is
|
||||
* provided to the "registerExtension" call as second argument. This second argument is used as a
|
||||
* proxy and enqueired if the method to override exists in this proxy before calling it.
|
||||
* of the extension behaviour. In c++ this is as simple as overriding the provided virtual
|
||||
* functions. In python a class method must be provided which has the same name as the method to
|
||||
* override. This method must not necessarily be in the object that is extended, it must be in the
|
||||
* object which is provided to the "registerExtension" call as second argument. This second argument
|
||||
* is used as a proxy and enqueired if the method to override exists in this proxy before calling
|
||||
* it.
|
||||
*
|
||||
* For information on howto create extension see the documentation of Extension
|
||||
*/
|
||||
class AppExport ExtensionContainer : public App::PropertyContainer
|
||||
class AppExport ExtensionContainer: public App::PropertyContainer
|
||||
{
|
||||
|
||||
TYPESYSTEM_HEADER_WITH_OVERRIDE();
|
||||
|
||||
public:
|
||||
|
||||
using ExtensionIterator = std::map<Base::Type, App::Extension*>::iterator;
|
||||
|
||||
ExtensionContainer();
|
||||
~ExtensionContainer() override;
|
||||
|
||||
void registerExtension(Base::Type extension, App::Extension* ext);
|
||||
//returns first of type (or derived from if set to true) and throws otherwise
|
||||
bool hasExtension(Base::Type, bool derived=true) const;
|
||||
//this version does not check derived classes
|
||||
// returns first of type (or derived from if set to true) and throws otherwise
|
||||
bool hasExtension(Base::Type, bool derived = true) const;
|
||||
// this version does not check derived classes
|
||||
bool hasExtension(const std::string& name) const;
|
||||
bool hasExtensions() const;
|
||||
App::Extension* getExtension(Base::Type, bool derived = true, bool no_except=false) const;
|
||||
//this version does not check derived classes
|
||||
App::Extension* getExtension(Base::Type, bool derived = true, bool no_except = false) const;
|
||||
// this version does not check derived classes
|
||||
App::Extension* getExtension(const std::string& name) const;
|
||||
// this version checks for derived types and doesn't throw
|
||||
template<typename ExtensionT>
|
||||
ExtensionT* getExtension() const {
|
||||
return static_cast<ExtensionT*>(getExtension(ExtensionT::getExtensionClassTypeId(), true, true));
|
||||
ExtensionT* getExtension() const
|
||||
{
|
||||
return static_cast<ExtensionT*>(
|
||||
getExtension(ExtensionT::getExtensionClassTypeId(), true, true));
|
||||
}
|
||||
|
||||
//returns first of type (or derived from) and throws otherwise
|
||||
// returns first of type (or derived from) and throws otherwise
|
||||
template<typename ExtensionT>
|
||||
ExtensionT* getExtensionByType(bool no_except=false, bool derived=true) const {
|
||||
return static_cast<ExtensionT*>(getExtension(ExtensionT::getExtensionClassTypeId(),derived,no_except));
|
||||
ExtensionT* getExtensionByType(bool no_except = false, bool derived = true) const
|
||||
{
|
||||
return static_cast<ExtensionT*>(
|
||||
getExtension(ExtensionT::getExtensionClassTypeId(), derived, no_except));
|
||||
}
|
||||
|
||||
//get all extensions which have the given base class
|
||||
// get all extensions which have the given base class
|
||||
std::vector<Extension*> getExtensionsDerivedFrom(Base::Type type) const;
|
||||
template<typename ExtensionT>
|
||||
std::vector<ExtensionT*> getExtensionsDerivedFromType() const {
|
||||
std::vector<ExtensionT*> getExtensionsDerivedFromType() const
|
||||
{
|
||||
std::vector<ExtensionT*> typevec;
|
||||
for(const auto& entry : _extensions) {
|
||||
if(entry.first.isDerivedFrom(ExtensionT::getExtensionClassTypeId()))
|
||||
for (const auto& entry : _extensions) {
|
||||
if (entry.first.isDerivedFrom(ExtensionT::getExtensionClassTypeId())) {
|
||||
typevec.push_back(static_cast<ExtensionT*>(entry.second));
|
||||
}
|
||||
}
|
||||
return typevec;
|
||||
}
|
||||
|
||||
ExtensionIterator extensionBegin() {return _extensions.begin();}
|
||||
ExtensionIterator extensionEnd() {return _extensions.end();}
|
||||
ExtensionIterator extensionBegin()
|
||||
{
|
||||
return _extensions.begin();
|
||||
}
|
||||
ExtensionIterator extensionEnd()
|
||||
{
|
||||
return _extensions.end();
|
||||
}
|
||||
|
||||
|
||||
/** @name Access properties */
|
||||
//@{
|
||||
/// find a property by its name
|
||||
Property *getPropertyByName(const char* name) const override;
|
||||
Property* getPropertyByName(const char* name) const override;
|
||||
/// get the name of a property
|
||||
const char* getPropertyName(const Property* prop) const override;
|
||||
/// get all properties of the class (including properties of the parent)
|
||||
void getPropertyMap(std::map<std::string,Property*> &Map) const override;
|
||||
void getPropertyMap(std::map<std::string, Property*>& Map) const override;
|
||||
/// get all properties of the class (including properties of the parent)
|
||||
void getPropertyList(std::vector<Property*> &List) const override;
|
||||
void getPropertyList(std::vector<Property*>& List) const override;
|
||||
|
||||
/// get the Type of a Property
|
||||
short getPropertyType(const Property* prop) const override;
|
||||
/// get the Type of a named Property
|
||||
short getPropertyType(const char *name) const override;
|
||||
short getPropertyType(const char* name) const override;
|
||||
/// get the Group of a Property
|
||||
const char* getPropertyGroup(const Property* prop) const override;
|
||||
/// get the Group of a named Property
|
||||
const char* getPropertyGroup(const char *name) const override;
|
||||
const char* getPropertyGroup(const char* name) const override;
|
||||
/// get the Group of a Property
|
||||
const char* getPropertyDocumentation(const Property* prop) const override;
|
||||
/// get the Group of a named Property
|
||||
const char* getPropertyDocumentation(const char *name) const override;
|
||||
const char* getPropertyDocumentation(const char* name) const override;
|
||||
//@}
|
||||
|
||||
void onChanged(const Property*) override;
|
||||
@@ -186,43 +199,50 @@ public:
|
||||
void Save(Base::Writer& writer) const override;
|
||||
void Restore(Base::XMLReader& reader) override;
|
||||
|
||||
//those methods save/restore the dynamic extensions without handling properties, which is something
|
||||
//done by the default Save/Restore methods.
|
||||
// those methods save/restore the dynamic extensions without handling properties, which is
|
||||
// something done by the default Save/Restore methods.
|
||||
void saveExtensions(Base::Writer& writer) const;
|
||||
void restoreExtensions(Base::XMLReader& reader);
|
||||
|
||||
/** Extends the rules for handling property name changed, so that extensions are given an opportunity to handle it.
|
||||
* If an extension handles a change, neither the rest of the extensions, nor the container itself get to handle it.
|
||||
/** Extends the rules for handling property name changed, so that extensions are given an
|
||||
* opportunity to handle it. If an extension handles a change, neither the rest of the
|
||||
* extensions, nor the container itself get to handle it.
|
||||
*
|
||||
* Extensions get their extensionHandleChangedPropertyName() called.
|
||||
*
|
||||
* If no extension handles the request, then the containers handleChangedPropertyName() is called.
|
||||
* If no extension handles the request, then the containers handleChangedPropertyName() is
|
||||
* called.
|
||||
*/
|
||||
void handleChangedPropertyName(Base::XMLReader &reader, const char * TypeName, const char *PropName) override;
|
||||
/** Extends the rules for handling property type changed, so that extensions are given an opportunity to handle it.
|
||||
* If an extension handles a change, neither the rest of the extensions, nor the container itself get to handle it.
|
||||
void handleChangedPropertyName(Base::XMLReader& reader,
|
||||
const char* TypeName,
|
||||
const char* PropName) override;
|
||||
/** Extends the rules for handling property type changed, so that extensions are given an
|
||||
* opportunity to handle it. If an extension handles a change, neither the rest of the
|
||||
* extensions, nor the container itself get to handle it.
|
||||
*
|
||||
* Extensions get their extensionHandleChangedPropertyType() called.
|
||||
*
|
||||
* If no extension handles the request, then the containers handleChangedPropertyType() is called.
|
||||
* If no extension handles the request, then the containers handleChangedPropertyType() is
|
||||
* called.
|
||||
*/
|
||||
void handleChangedPropertyType(Base::XMLReader &reader, const char * TypeName, Property * prop) override;
|
||||
void handleChangedPropertyType(Base::XMLReader& reader,
|
||||
const char* TypeName,
|
||||
Property* prop) override;
|
||||
|
||||
private:
|
||||
//stored extensions
|
||||
// stored extensions
|
||||
std::map<Base::Type, App::Extension*> _extensions;
|
||||
};
|
||||
|
||||
#define PROPERTY_HEADER_WITH_EXTENSIONS(_class_) \
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(_class)
|
||||
#define PROPERTY_HEADER_WITH_EXTENSIONS(_class_) PROPERTY_HEADER_WITH_OVERRIDE(_class)
|
||||
|
||||
/// We make sure that the PropertyData of the container is not connected to the one of the extension
|
||||
#define PROPERTY_SOURCE_WITH_EXTENSIONS(_class_, _parentclass_) \
|
||||
#define PROPERTY_SOURCE_WITH_EXTENSIONS(_class_, _parentclass_) \
|
||||
PROPERTY_SOURCE(_class_, _parentclass_)
|
||||
|
||||
#define PROPERTY_SOURCE_ABSTRACT_WITH_EXTENSIONS(_class_, _parentclass_) \
|
||||
#define PROPERTY_SOURCE_ABSTRACT_WITH_EXTENSIONS(_class_, _parentclass_) \
|
||||
PROPERTY_SOURCE_ABSTRACT(_class_, _parentclass_)
|
||||
|
||||
} //App
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_EXTENSIONCONTAINER_H
|
||||
#endif // APP_EXTENSIONCONTAINER_H
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="PropertyContainerPy"
|
||||
Name="ExtensionContainerPy"
|
||||
TwinPointer="ExtensionContainer"
|
||||
Twin="ExtensionContainer"
|
||||
Include="App/ExtensionContainer.h"
|
||||
Namespace="App"
|
||||
FatherInclude="App/PropertyContainerPy.h"
|
||||
<PythonExport
|
||||
Father="PropertyContainerPy"
|
||||
Name="ExtensionContainerPy"
|
||||
TwinPointer="ExtensionContainer"
|
||||
Twin="ExtensionContainer"
|
||||
Include="App/ExtensionContainer.h"
|
||||
Namespace="App"
|
||||
FatherInclude="App/PropertyContainerPy.h"
|
||||
FatherNamespace="App"
|
||||
Initialization="true"
|
||||
Constructor = "true">
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <sstream>
|
||||
#include <sstream>
|
||||
#endif
|
||||
|
||||
#include "Application.h"
|
||||
@@ -41,22 +41,24 @@ std::string ExtensionContainerPy::representation() const
|
||||
return {"<extension>"};
|
||||
}
|
||||
|
||||
int ExtensionContainerPy::initialization() {
|
||||
int ExtensionContainerPy::initialization()
|
||||
{
|
||||
|
||||
if (!this->ob_type->tp_dict) {
|
||||
if (PyType_Ready(this->ob_type) < 0)
|
||||
if (PyType_Ready(this->ob_type) < 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionContainer::ExtensionIterator it = this->getExtensionContainerPtr()->extensionBegin();
|
||||
for(; it != this->getExtensionContainerPtr()->extensionEnd(); ++it) {
|
||||
for (; it != this->getExtensionContainerPtr()->extensionEnd(); ++it) {
|
||||
|
||||
// The PyTypeObject is shared by all instances of this type and therefore
|
||||
// we have to add new methods only once.
|
||||
PyObject* obj = (*it).second->getExtensionPyObject();
|
||||
PyMethodDef* meth = obj->ob_type->tp_methods;
|
||||
PyTypeObject *type = this->ob_type;
|
||||
PyObject *dict = type->tp_dict;
|
||||
PyTypeObject* type = this->ob_type;
|
||||
PyObject* dict = type->tp_dict;
|
||||
|
||||
// make sure to do the initialization only once
|
||||
if (meth->ml_name) {
|
||||
@@ -67,12 +69,14 @@ int ExtensionContainerPy::initialization() {
|
||||
// to an instance
|
||||
Py_INCREF(dict);
|
||||
while (meth->ml_name) {
|
||||
PyObject *func;
|
||||
PyObject* func;
|
||||
func = PyCFunction_New(meth, 0);
|
||||
if (!func)
|
||||
if (!func) {
|
||||
break;
|
||||
if (PyDict_SetItemString(dict, meth->ml_name, func) < 0)
|
||||
}
|
||||
if (PyDict_SetItemString(dict, meth->ml_name, func) < 0) {
|
||||
break;
|
||||
}
|
||||
Py_DECREF(func);
|
||||
++meth;
|
||||
}
|
||||
@@ -86,20 +90,22 @@ int ExtensionContainerPy::initialization() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ExtensionContainerPy::finalization() {
|
||||
/*
|
||||
//we need to delete all added python extensions, as we are the owner!
|
||||
ExtensionContainer::ExtensionIterator it = this->getExtensionContainerPtr()->extensionBegin();
|
||||
for(; it != this->getExtensionContainerPtr()->extensionEnd(); ++it) {
|
||||
if((*it).second->isPythonExtension())
|
||||
delete (*it).second;
|
||||
}*/
|
||||
int ExtensionContainerPy::finalization()
|
||||
{
|
||||
/*
|
||||
//we need to delete all added python extensions, as we are the owner!
|
||||
ExtensionContainer::ExtensionIterator it =
|
||||
this->getExtensionContainerPtr()->extensionBegin(); for(; it !=
|
||||
this->getExtensionContainerPtr()->extensionEnd(); ++it) {
|
||||
if((*it).second->isPythonExtension())
|
||||
delete (*it).second;
|
||||
}*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
PyObject* ExtensionContainerPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper
|
||||
PyObject* ExtensionContainerPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper
|
||||
{
|
||||
// create a new instance of @self.export.Name@ and the Twin object
|
||||
// create a new instance of @self.export.Name@ and the Twin object
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -109,7 +115,7 @@ int ExtensionContainerPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject *ExtensionContainerPy::getCustomAttributes(const char* attr) const
|
||||
PyObject* ExtensionContainerPy::getCustomAttributes(const char* attr) const
|
||||
{
|
||||
if (Base::streq(attr, "__dict__")) {
|
||||
PyObject* dict = PyDict_New();
|
||||
@@ -119,12 +125,13 @@ PyObject *ExtensionContainerPy::getCustomAttributes(const char* attr) const
|
||||
Py_DECREF(props);
|
||||
}
|
||||
|
||||
ExtensionContainer::ExtensionIterator it = this->getExtensionContainerPtr()->extensionBegin();
|
||||
ExtensionContainer::ExtensionIterator it =
|
||||
this->getExtensionContainerPtr()->extensionBegin();
|
||||
for (; it != this->getExtensionContainerPtr()->extensionEnd(); ++it) {
|
||||
// The PyTypeObject is shared by all instances of this type and therefore
|
||||
// we have to add new methods only once.
|
||||
PyObject* obj = (*it).second->getExtensionPyObject();
|
||||
PyTypeObject *tp = Py_TYPE(obj);
|
||||
PyTypeObject* tp = Py_TYPE(obj);
|
||||
if (tp && tp->tp_dict) {
|
||||
Py_XINCREF(tp->tp_dict);
|
||||
PyDict_Merge(dict, tp->tp_dict, 0);
|
||||
@@ -139,13 +146,13 @@ PyObject *ExtensionContainerPy::getCustomAttributes(const char* attr) const
|
||||
// Py_FindMethod is successful then a PyCFunction_New instance is returned
|
||||
// with the PyObject pointer of the extension to make sure the method will
|
||||
// be called for the correct instance.
|
||||
PyObject *func = nullptr;
|
||||
PyObject* func = nullptr;
|
||||
ExtensionContainer::ExtensionIterator it = this->getExtensionContainerPtr()->extensionBegin();
|
||||
for (; it != this->getExtensionContainerPtr()->extensionEnd(); ++it) {
|
||||
// The PyTypeObject is shared by all instances of this type and therefore
|
||||
// we have to add new methods only once.
|
||||
PyObject* obj = (*it).second->getExtensionPyObject();
|
||||
PyObject *nameobj = PyUnicode_FromString(attr);
|
||||
PyObject* nameobj = PyUnicode_FromString(attr);
|
||||
func = PyObject_GenericGetAttr(obj, nameobj);
|
||||
Py_DECREF(nameobj);
|
||||
Py_DECREF(obj);
|
||||
@@ -153,33 +160,36 @@ PyObject *ExtensionContainerPy::getCustomAttributes(const char* attr) const
|
||||
PyCFunctionObject* cfunc = reinterpret_cast<PyCFunctionObject*>(func);
|
||||
|
||||
// OK, that's what we wanted
|
||||
if (cfunc->m_self == obj)
|
||||
if (cfunc->m_self == obj) {
|
||||
break;
|
||||
}
|
||||
// otherwise cleanup the result again
|
||||
Py_DECREF(func);
|
||||
func = nullptr;
|
||||
}
|
||||
PyErr_Clear(); // clear the error set inside Py_FindMethod
|
||||
PyErr_Clear(); // clear the error set inside Py_FindMethod
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
int ExtensionContainerPy::setCustomAttributes(const char* /*attr*/, PyObject * /*obj*/)
|
||||
int ExtensionContainerPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* ExtensionContainerPy::hasExtension(PyObject *args) {
|
||||
PyObject* ExtensionContainerPy::hasExtension(PyObject* args)
|
||||
{
|
||||
|
||||
char *type;
|
||||
PyObject *deriv = Py_True;
|
||||
if (!PyArg_ParseTuple(args, "s|O!", &type, &PyBool_Type, &deriv))
|
||||
char* type;
|
||||
PyObject* deriv = Py_True;
|
||||
if (!PyArg_ParseTuple(args, "s|O!", &type, &PyBool_Type, &deriv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//get the extension type asked for
|
||||
// get the extension type asked for
|
||||
bool derived = Base::asBoolean(deriv);
|
||||
Base::Type extension = Base::Type::fromName(type);
|
||||
Base::Type extension = Base::Type::fromName(type);
|
||||
if (extension.isBad() || !extension.isDerivedFrom(App::Extension::getExtensionClassTypeId())) {
|
||||
std::stringstream str;
|
||||
str << "No extension found of type '" << type << "'" << std::ends;
|
||||
@@ -194,30 +204,34 @@ PyObject* ExtensionContainerPy::hasExtension(PyObject *args) {
|
||||
return PyBool_FromLong(val ? 1 : 0);
|
||||
}
|
||||
|
||||
PyObject* ExtensionContainerPy::addExtension(PyObject *args) {
|
||||
PyObject* ExtensionContainerPy::addExtension(PyObject* args)
|
||||
{
|
||||
|
||||
char *typeId;
|
||||
char* typeId;
|
||||
PyObject* proxy = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "s|O", &typeId, &proxy))
|
||||
if (!PyArg_ParseTuple(args, "s|O", &typeId, &proxy)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (proxy) {
|
||||
PyErr_SetString(PyExc_DeprecationWarning, "Second argument is deprecated. It is ignored and will be removed in future versions. "
|
||||
"The default Python feature proxy is used for extension method overrides.");
|
||||
PyErr_SetString(
|
||||
PyExc_DeprecationWarning,
|
||||
"Second argument is deprecated. It is ignored and will be removed in future versions. "
|
||||
"The default Python feature proxy is used for extension method overrides.");
|
||||
PyErr_Print();
|
||||
}
|
||||
|
||||
//get the extension type asked for
|
||||
Base::Type extension = Base::Type::fromName(typeId);
|
||||
// get the extension type asked for
|
||||
Base::Type extension = Base::Type::fromName(typeId);
|
||||
if (extension.isBad() || !extension.isDerivedFrom(App::Extension::getExtensionClassTypeId())) {
|
||||
std::stringstream str;
|
||||
str << "No extension found of type '" << typeId << "'" << std::ends;
|
||||
throw Py::TypeError(str.str());
|
||||
}
|
||||
|
||||
//register the extension
|
||||
// register the extension
|
||||
App::Extension* ext = static_cast<App::Extension*>(extension.createInstance());
|
||||
//check if this really is a python extension!
|
||||
// check if this really is a python extension!
|
||||
if (!ext->isPythonExtension()) {
|
||||
delete ext;
|
||||
std::stringstream str;
|
||||
@@ -232,8 +246,8 @@ PyObject* ExtensionContainerPy::addExtension(PyObject *args) {
|
||||
// we have to add new methods only once.
|
||||
PyObject* obj = ext->getExtensionPyObject();
|
||||
PyMethodDef* meth = obj->ob_type->tp_methods;
|
||||
PyTypeObject *type = this->ob_type;
|
||||
PyObject *dict = type->tp_dict;
|
||||
PyTypeObject* type = this->ob_type;
|
||||
PyObject* dict = type->tp_dict;
|
||||
|
||||
// make sure to do the initialization only once
|
||||
if (meth->ml_name) {
|
||||
@@ -244,12 +258,14 @@ PyObject* ExtensionContainerPy::addExtension(PyObject *args) {
|
||||
// to an instance
|
||||
Py_INCREF(dict);
|
||||
while (meth->ml_name) {
|
||||
PyObject *func;
|
||||
PyObject* func;
|
||||
func = PyCFunction_New(meth, 0);
|
||||
if (!func)
|
||||
if (!func) {
|
||||
break;
|
||||
if (PyDict_SetItemString(dict, meth->ml_name, func) < 0)
|
||||
}
|
||||
if (PyDict_SetItemString(dict, meth->ml_name, func) < 0) {
|
||||
break;
|
||||
}
|
||||
Py_DECREF(func);
|
||||
++meth;
|
||||
}
|
||||
@@ -259,8 +275,8 @@ PyObject* ExtensionContainerPy::addExtension(PyObject *args) {
|
||||
}
|
||||
|
||||
Py_DECREF(obj);
|
||||
|
||||
//throw the appropriate event
|
||||
|
||||
// throw the appropriate event
|
||||
GetApplication().signalAddedDynamicExtension(*getExtensionContainerPtr(), typeId);
|
||||
|
||||
Py_Return;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="PyObjectBase"
|
||||
Name="ExtensionPy"
|
||||
TwinPointer="Extension"
|
||||
Twin="Extension"
|
||||
Include="App/Extension.h"
|
||||
Namespace="App"
|
||||
FatherInclude="Base/PyObjectBase.h"
|
||||
<PythonExport
|
||||
Father="PyObjectBase"
|
||||
Name="ExtensionPy"
|
||||
TwinPointer="Extension"
|
||||
Twin="Extension"
|
||||
Include="App/Extension.h"
|
||||
Namespace="App"
|
||||
FatherInclude="Base/PyObjectBase.h"
|
||||
FatherNamespace="Base">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Stefan Troeger" EMail="stefantroeger@gmx.net" />
|
||||
|
||||
@@ -37,12 +37,12 @@ std::string ExtensionPy::representation() const
|
||||
return {"<extension>"};
|
||||
}
|
||||
|
||||
PyObject *ExtensionPy::getCustomAttributes(const char* /*attr*/) const
|
||||
PyObject* ExtensionPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int ExtensionPy::setCustomAttributes(const char* /*attr*/, PyObject * /*obj*/)
|
||||
int ExtensionPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -28,21 +28,23 @@
|
||||
#include "Extension.h"
|
||||
#include "PropertyPythonObject.h"
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
|
||||
/**
|
||||
* Generic Python extension class which allows every extension derived
|
||||
* class to behave as a Python extension -- simply by subclassing.
|
||||
*/
|
||||
template <class ExtensionT>
|
||||
class ExtensionPythonT : public ExtensionT //NOLINT
|
||||
template<class ExtensionT>
|
||||
class ExtensionPythonT: public ExtensionT // NOLINT
|
||||
{
|
||||
EXTENSION_PROPERTY_HEADER_WITH_OVERRIDE(App::ExtensionPythonT<ExtensionT>);
|
||||
|
||||
public:
|
||||
using Inherited = ExtensionT;
|
||||
|
||||
ExtensionPythonT() {
|
||||
ExtensionPythonT()
|
||||
{
|
||||
ExtensionT::m_isPythonExtension = true;
|
||||
ExtensionT::initExtensionType(ExtensionPythonT::getExtensionClassTypeId());
|
||||
}
|
||||
@@ -50,73 +52,72 @@ public:
|
||||
|
||||
ExtensionPythonT(const ExtensionPythonT&) = delete;
|
||||
ExtensionPythonT(ExtensionPythonT&&) = delete;
|
||||
ExtensionPythonT& operator= (const ExtensionPythonT&) = delete;
|
||||
ExtensionPythonT& operator= (ExtensionPythonT&&) = delete;
|
||||
ExtensionPythonT& operator=(const ExtensionPythonT&) = delete;
|
||||
ExtensionPythonT& operator=(ExtensionPythonT&&) = delete;
|
||||
};
|
||||
|
||||
using ExtensionPython = ExtensionPythonT<App::Extension>;
|
||||
|
||||
// Helper macros to define python extensions
|
||||
#define EXTENSION_PROXY_FIRST(function) \
|
||||
Base::PyGILStateLocker lock;\
|
||||
Py::Object result;\
|
||||
try {\
|
||||
Property* proxy = this->getExtendedContainer()->getPropertyByName("Proxy");\
|
||||
if (proxy && proxy->is<PropertyPythonObject>()) {\
|
||||
Py::Object feature = static_cast<PropertyPythonObject*>(proxy)->getValue();\
|
||||
if (feature.hasAttr(std::string("function"))) {\
|
||||
if (feature.hasAttr("__object__")) {\
|
||||
#define EXTENSION_PROXY_FIRST(function) \
|
||||
Base::PyGILStateLocker lock; \
|
||||
Py::Object result; \
|
||||
try { \
|
||||
Property* proxy = this->getExtendedContainer()->getPropertyByName("Proxy"); \
|
||||
if (proxy && proxy->is<PropertyPythonObject>()) { \
|
||||
Py::Object feature = static_cast<PropertyPythonObject*>(proxy)->getValue(); \
|
||||
if (feature.hasAttr(std::string("function"))) { \
|
||||
if (feature.hasAttr("__object__")) { \
|
||||
Py::Callable method(feature.getAttr(std::string("function")));
|
||||
|
||||
|
||||
#define EXTENSION_PROXY_SECOND(function) \
|
||||
result = method.apply(args); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
Py::Callable method(feature.getAttr(std::string("function")));
|
||||
|
||||
|
||||
#define EXTENSION_PROXY_SECOND(function)\
|
||||
result = method.apply(args);\
|
||||
}\
|
||||
else {\
|
||||
Py::Callable method(feature.getAttr(std::string("function")));
|
||||
|
||||
#define EXTENSION_PROXY_THIRD()\
|
||||
result = method.apply(args);\
|
||||
}\
|
||||
}\
|
||||
}\
|
||||
}\
|
||||
catch (Py::Exception&) {\
|
||||
Base::PyException e;\
|
||||
e.ReportException();\
|
||||
#define EXTENSION_PROXY_THIRD() \
|
||||
result = method.apply(args); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
catch (Py::Exception&) \
|
||||
{ \
|
||||
Base::PyException e; \
|
||||
e.ReportException(); \
|
||||
}
|
||||
|
||||
#define EXTENSION_PROXY_NOARG(function)\
|
||||
EXTENSION_PROXY_FIRST(function) \
|
||||
Py::Tuple args;\
|
||||
EXTENSION_PROXY_SECOND(function) \
|
||||
Py::Tuple args(1);\
|
||||
args.setItem(0, Py::Object(this->getExtensionPyObject(), true));\
|
||||
#define EXTENSION_PROXY_NOARG(function) \
|
||||
EXTENSION_PROXY_FIRST(function) \
|
||||
Py::Tuple args; \
|
||||
EXTENSION_PROXY_SECOND(function) \
|
||||
Py::Tuple args(1); \
|
||||
args.setItem(0, Py::Object(this->getExtensionPyObject(), true)); \
|
||||
EXTENSION_PROXY_THIRD()
|
||||
|
||||
#define EXTENSION_PROXY_ONEARG(function, arg)\
|
||||
EXTENSION_PROXY_FIRST(function) \
|
||||
Py::Tuple args;\
|
||||
args.setItem(0, arg); \
|
||||
EXTENSION_PROXY_SECOND(function) \
|
||||
Py::Tuple args(2);\
|
||||
args.setItem(0, Py::Object(this->getExtensionPyObject(), true));\
|
||||
args.setItem(1, arg); \
|
||||
#define EXTENSION_PROXY_ONEARG(function, arg) \
|
||||
EXTENSION_PROXY_FIRST(function) \
|
||||
Py::Tuple args; \
|
||||
args.setItem(0, arg); \
|
||||
EXTENSION_PROXY_SECOND(function) \
|
||||
Py::Tuple args(2); \
|
||||
args.setItem(0, Py::Object(this->getExtensionPyObject(), true)); \
|
||||
args.setItem(1, arg); \
|
||||
EXTENSION_PROXY_THIRD()
|
||||
|
||||
#define EXTENSION_PYTHON_OVERRIDE_VOID_NOARGS(function)\
|
||||
virtual void function() override {\
|
||||
EXTENSION_PROXY_NOARGS(function)\
|
||||
#define EXTENSION_PYTHON_OVERRIDE_VOID_NOARGS(function) \
|
||||
virtual void function() override { EXTENSION_PROXY_NOARGS(function) };
|
||||
|
||||
#define EXTENSION_PYTHON_OVERRIDE_OBJECT_NOARGS(function) \
|
||||
virtual PyObject* function() override \
|
||||
{ \
|
||||
EXTENSION_PROXY_NOARGS(function) \
|
||||
return res.ptr(); \
|
||||
};
|
||||
|
||||
#define EXTENSION_PYTHON_OVERRIDE_OBJECT_NOARGS(function)\
|
||||
virtual PyObject* function() override {\
|
||||
EXTENSION_PROXY_NOARGS(function)\
|
||||
return res.ptr();\
|
||||
};
|
||||
} // namespace App
|
||||
|
||||
} //App
|
||||
|
||||
#endif // APP_EXTENSIONPYTHON_H
|
||||
#endif // APP_EXTENSIONPYTHON_H
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef APP_FEATURECUSTOM_H
|
||||
#define APP_FEATURECUSTOM_H
|
||||
|
||||
@@ -41,8 +40,8 @@ class Property;
|
||||
* it has no support for in Python written feature classes.
|
||||
* @author Werner Mayer
|
||||
*/
|
||||
template <class FeatureT>
|
||||
class FeatureCustomT : public FeatureT //NOLINT
|
||||
template<class FeatureT>
|
||||
class FeatureCustomT: public FeatureT // NOLINT
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(App::FeatureCustomT<FeatureT>);
|
||||
|
||||
@@ -53,46 +52,55 @@ public:
|
||||
|
||||
/** @name methods override DocumentObject */
|
||||
//@{
|
||||
short mustExecute() const override {
|
||||
short mustExecute() const override
|
||||
{
|
||||
return FeatureT::mustExecute();
|
||||
}
|
||||
/// recalculate the Feature
|
||||
DocumentObjectExecReturn *execute() override {
|
||||
DocumentObjectExecReturn* execute() override
|
||||
{
|
||||
return FeatureT::execute();
|
||||
}
|
||||
/// returns the type name of the ViewProvider
|
||||
const char* getViewProviderName() const override {
|
||||
const char* getViewProviderName() const override
|
||||
{
|
||||
return FeatureT::getViewProviderName();
|
||||
}
|
||||
|
||||
PyObject *getPyObject() override {
|
||||
PyObject* getPyObject() override
|
||||
{
|
||||
return FeatureT::getPyObject();
|
||||
}
|
||||
void setPyObject(PyObject *obj) override {
|
||||
void setPyObject(PyObject* obj) override
|
||||
{
|
||||
FeatureT::setPyObject(obj);
|
||||
}
|
||||
|
||||
protected:
|
||||
void onBeforeChange(const Property* prop) override {
|
||||
void onBeforeChange(const Property* prop) override
|
||||
{
|
||||
FeatureT::onBeforeChange(prop);
|
||||
}
|
||||
void onChanged(const Property* prop) override {
|
||||
void onChanged(const Property* prop) override
|
||||
{
|
||||
FeatureT::onChanged(prop);
|
||||
}
|
||||
void onDocumentRestored() override {
|
||||
void onDocumentRestored() override
|
||||
{
|
||||
FeatureT::onDocumentRestored();
|
||||
}
|
||||
void onSettingDocument() override {
|
||||
void onSettingDocument() override
|
||||
{
|
||||
FeatureT::onSettingDocument();
|
||||
}
|
||||
|
||||
public:
|
||||
FeatureCustomT(const FeatureCustomT&) = delete;
|
||||
FeatureCustomT(FeatureCustomT&&) = delete;
|
||||
FeatureCustomT& operator= (const FeatureCustomT&) = delete;
|
||||
FeatureCustomT& operator= (FeatureCustomT&&) = delete;
|
||||
FeatureCustomT& operator=(const FeatureCustomT&) = delete;
|
||||
FeatureCustomT& operator=(FeatureCustomT&&) = delete;
|
||||
};
|
||||
|
||||
} //namespace App
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_FEATURECUSTOM_H
|
||||
#endif // APP_FEATURECUSTOM_H
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
# include <sstream>
|
||||
#include <sstream>
|
||||
#endif
|
||||
|
||||
#include <App/DocumentObjectPy.h>
|
||||
@@ -39,8 +39,7 @@ using namespace App;
|
||||
|
||||
FeaturePythonImp::FeaturePythonImp(App::DocumentObject* o)
|
||||
: object(o)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
FeaturePythonImp::~FeaturePythonImp()
|
||||
{
|
||||
@@ -56,7 +55,8 @@ FeaturePythonImp::~FeaturePythonImp()
|
||||
}
|
||||
}
|
||||
|
||||
void FeaturePythonImp::init(PyObject *pyobj) {
|
||||
void FeaturePythonImp::init(PyObject* pyobj)
|
||||
{
|
||||
Base::PyGILStateLocker lock;
|
||||
has__object__ = !!PyObject_HasAttrString(pyobj, "__object__");
|
||||
|
||||
@@ -66,11 +66,11 @@ void FeaturePythonImp::init(PyObject *pyobj) {
|
||||
FC_PY_FEATURE_PYTHON
|
||||
}
|
||||
|
||||
#define FC_PY_CALL_CHECK(_name) _FC_PY_CALL_CHECK(_name,return(false))
|
||||
#define FC_PY_CALL_CHECK(_name) _FC_PY_CALL_CHECK(_name, return (false))
|
||||
|
||||
/*!
|
||||
Calls the execute() method of the Python feature class. If the Python feature class doesn't have an execute()
|
||||
method or if it returns False this method also return false and true otherwise.
|
||||
Calls the execute() method of the Python feature class. If the Python feature class doesn't have an
|
||||
execute() method or if it returns False this method also return false and true otherwise.
|
||||
*/
|
||||
bool FeaturePythonImp::execute()
|
||||
{
|
||||
@@ -79,16 +79,18 @@ bool FeaturePythonImp::execute()
|
||||
try {
|
||||
if (has__object__) {
|
||||
Py::Object res = Base::pyCall(py_execute.ptr());
|
||||
if (res.isBoolean() && !res.isTrue())
|
||||
if (res.isBoolean() && !res.isTrue()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::Object(object->getPyObject(), true));
|
||||
Py::Object res = Base::pyCall(py_execute.ptr(),args.ptr());
|
||||
if (res.isBoolean() && !res.isTrue())
|
||||
Py::Object res = Base::pyCall(py_execute.ptr(), args.ptr());
|
||||
if (res.isBoolean() && !res.isTrue()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -97,7 +99,7 @@ bool FeaturePythonImp::execute()
|
||||
PyErr_Clear();
|
||||
return false;
|
||||
}
|
||||
Base::PyException::ThrowException(); // extract the Python error text
|
||||
Base::PyException::ThrowException(); // extract the Python error text
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -115,12 +117,12 @@ bool FeaturePythonImp::mustExecute() const
|
||||
else {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::Object(object->getPyObject(), true));
|
||||
Py::Object res(Base::pyCall(py_mustExecute.ptr(),args.ptr()));
|
||||
Py::Object res(Base::pyCall(py_mustExecute.ptr(), args.ptr()));
|
||||
return res.isTrue();
|
||||
}
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
return false;
|
||||
@@ -129,54 +131,58 @@ bool FeaturePythonImp::mustExecute() const
|
||||
|
||||
void FeaturePythonImp::onBeforeChange(const Property* prop)
|
||||
{
|
||||
if (py_onBeforeChange.isNone())
|
||||
if (py_onBeforeChange.isNone()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Run the execute method of the proxy object.
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
const char *prop_name = object->getPropertyName(prop);
|
||||
if (!prop_name)
|
||||
const char* prop_name = object->getPropertyName(prop);
|
||||
if (!prop_name) {
|
||||
return;
|
||||
}
|
||||
if (has__object__) {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::String(prop_name));
|
||||
Base::pyCall(py_onBeforeChange.ptr(),args.ptr());
|
||||
Base::pyCall(py_onBeforeChange.ptr(), args.ptr());
|
||||
}
|
||||
else {
|
||||
Py::Tuple args(2);
|
||||
args.setItem(0, Py::Object(object->getPyObject(), true));
|
||||
args.setItem(1, Py::String(prop_name));
|
||||
Base::pyCall(py_onBeforeChange.ptr(),args.ptr());
|
||||
Base::pyCall(py_onBeforeChange.ptr(), args.ptr());
|
||||
}
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
bool FeaturePythonImp::onBeforeChangeLabel(std::string &newLabel)
|
||||
bool FeaturePythonImp::onBeforeChangeLabel(std::string& newLabel)
|
||||
{
|
||||
if(py_onBeforeChangeLabel.isNone())
|
||||
if (py_onBeforeChangeLabel.isNone()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Run the execute method of the proxy object.
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::Tuple args(2);
|
||||
args.setItem(0, Py::Object(object->getPyObject(), true));
|
||||
args.setItem(1,Py::String(newLabel));
|
||||
Py::Object ret(Base::pyCall(py_onBeforeChangeLabel.ptr(),args.ptr()));
|
||||
if(!ret.isNone()) {
|
||||
if(!ret.isString())
|
||||
args.setItem(1, Py::String(newLabel));
|
||||
Py::Object ret(Base::pyCall(py_onBeforeChangeLabel.ptr(), args.ptr()));
|
||||
if (!ret.isNone()) {
|
||||
if (!ret.isString()) {
|
||||
throw Py::TypeError("onBeforeChangeLabel expects to return a string");
|
||||
}
|
||||
newLabel = ret.as_string();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
return false;
|
||||
@@ -184,35 +190,37 @@ bool FeaturePythonImp::onBeforeChangeLabel(std::string &newLabel)
|
||||
|
||||
void FeaturePythonImp::onChanged(const Property* prop)
|
||||
{
|
||||
if (py_onChanged.isNone())
|
||||
if (py_onChanged.isNone()) {
|
||||
return;
|
||||
}
|
||||
// Run the execute method of the proxy object.
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
const char *prop_name = object->getPropertyName(prop);
|
||||
if (!prop_name)
|
||||
const char* prop_name = object->getPropertyName(prop);
|
||||
if (!prop_name) {
|
||||
return;
|
||||
}
|
||||
if (has__object__) {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::String(prop_name));
|
||||
Base::pyCall(py_onChanged.ptr(),args.ptr());
|
||||
Base::pyCall(py_onChanged.ptr(), args.ptr());
|
||||
}
|
||||
else {
|
||||
Py::Tuple args(2);
|
||||
args.setItem(0, Py::Object(object->getPyObject(), true));
|
||||
args.setItem(1, Py::String(prop_name));
|
||||
Base::pyCall(py_onChanged.ptr(),args.ptr());
|
||||
Base::pyCall(py_onChanged.ptr(), args.ptr());
|
||||
}
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
void FeaturePythonImp::onDocumentRestored()
|
||||
{
|
||||
_FC_PY_CALL_CHECK(onDocumentRestored,return);
|
||||
_FC_PY_CALL_CHECK(onDocumentRestored, return);
|
||||
|
||||
// Run the execute method of the proxy object.
|
||||
Base::PyGILStateLocker lock;
|
||||
@@ -223,11 +231,11 @@ void FeaturePythonImp::onDocumentRestored()
|
||||
else {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::Object(object->getPyObject(), true));
|
||||
Base::pyCall(py_onDocumentRestored.ptr(),args.ptr());
|
||||
Base::pyCall(py_onDocumentRestored.ptr(), args.ptr());
|
||||
}
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -249,57 +257,71 @@ void FeaturePythonImp::unsetupObject()
|
||||
}
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
bool FeaturePythonImp::getSubObject(DocumentObject *&ret, const char *subname,
|
||||
PyObject **pyObj, Base::Matrix4D *_mat, bool transform, int depth) const
|
||||
bool FeaturePythonImp::getSubObject(DocumentObject*& ret,
|
||||
const char* subname,
|
||||
PyObject** pyObj,
|
||||
Base::Matrix4D* _mat,
|
||||
bool transform,
|
||||
int depth) const
|
||||
{
|
||||
FC_PY_CALL_CHECK(getSubObject);
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::Tuple args(6);
|
||||
args.setItem(0, Py::Object(object->getPyObject(), true));
|
||||
if(!subname) subname = "";
|
||||
args.setItem(1,Py::String(subname));
|
||||
args.setItem(2,Py::Int(pyObj?2:1));
|
||||
Base::MatrixPy *pyMat = new Base::MatrixPy(new Base::Matrix4D);
|
||||
if(_mat) *pyMat->getMatrixPtr() = *_mat;
|
||||
args.setItem(3,Py::asObject(pyMat));
|
||||
args.setItem(4,Py::Boolean(transform));
|
||||
args.setItem(5,Py::Int(depth));
|
||||
if (!subname) {
|
||||
subname = "";
|
||||
}
|
||||
args.setItem(1, Py::String(subname));
|
||||
args.setItem(2, Py::Int(pyObj ? 2 : 1));
|
||||
Base::MatrixPy* pyMat = new Base::MatrixPy(new Base::Matrix4D);
|
||||
if (_mat) {
|
||||
*pyMat->getMatrixPtr() = *_mat;
|
||||
}
|
||||
args.setItem(3, Py::asObject(pyMat));
|
||||
args.setItem(4, Py::Boolean(transform));
|
||||
args.setItem(5, Py::Int(depth));
|
||||
|
||||
Py::Object res(Base::pyCall(py_getSubObject.ptr(),args.ptr()));
|
||||
if(res.isNone()) {
|
||||
Py::Object res(Base::pyCall(py_getSubObject.ptr(), args.ptr()));
|
||||
if (res.isNone()) {
|
||||
ret = nullptr;
|
||||
return true;
|
||||
}
|
||||
if(!res.isTrue())
|
||||
if (!res.isTrue()) {
|
||||
return false;
|
||||
if(!res.isSequence())
|
||||
}
|
||||
if (!res.isSequence()) {
|
||||
throw Py::TypeError("getSubObject expects return type of tuple");
|
||||
}
|
||||
Py::Sequence seq(res);
|
||||
if(seq.length() < 2 ||
|
||||
(!seq.getItem(0).isNone() &&
|
||||
!PyObject_TypeCheck(seq.getItem(0).ptr(),&DocumentObjectPy::Type)) ||
|
||||
!PyObject_TypeCheck(seq.getItem(1).ptr(),&Base::MatrixPy::Type))
|
||||
{
|
||||
if (seq.length() < 2
|
||||
|| (!seq.getItem(0).isNone()
|
||||
&& !PyObject_TypeCheck(seq.getItem(0).ptr(), &DocumentObjectPy::Type))
|
||||
|| !PyObject_TypeCheck(seq.getItem(1).ptr(), &Base::MatrixPy::Type)) {
|
||||
throw Py::TypeError("getSubObject expects return type of (obj,matrix,pyobj)");
|
||||
}
|
||||
if(_mat)
|
||||
if (_mat) {
|
||||
*_mat = *static_cast<Base::MatrixPy*>(seq.getItem(1).ptr())->getMatrixPtr();
|
||||
if(pyObj) {
|
||||
if(seq.length()>2)
|
||||
*pyObj = Py::new_reference_to(seq.getItem(2));
|
||||
else
|
||||
*pyObj = Py::new_reference_to(Py::None());
|
||||
}
|
||||
if(seq.getItem(0).isNone())
|
||||
if (pyObj) {
|
||||
if (seq.length() > 2) {
|
||||
*pyObj = Py::new_reference_to(seq.getItem(2));
|
||||
}
|
||||
else {
|
||||
*pyObj = Py::new_reference_to(Py::None());
|
||||
}
|
||||
}
|
||||
if (seq.getItem(0).isNone()) {
|
||||
ret = nullptr;
|
||||
else
|
||||
}
|
||||
else {
|
||||
ret = static_cast<DocumentObjectPy*>(seq.getItem(0).ptr())->getDocumentObjectPtr();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
@@ -307,30 +329,34 @@ bool FeaturePythonImp::getSubObject(DocumentObject *&ret, const char *subname,
|
||||
PyErr_Clear();
|
||||
return false;
|
||||
}
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
ret = nullptr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool FeaturePythonImp::getSubObjects(std::vector<std::string> &ret, int reason) const {
|
||||
bool FeaturePythonImp::getSubObjects(std::vector<std::string>& ret, int reason) const
|
||||
{
|
||||
FC_PY_CALL_CHECK(getSubObjects);
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::Tuple args(2);
|
||||
args.setItem(0, Py::Object(object->getPyObject(), true));
|
||||
args.setItem(1, Py::Int(reason));
|
||||
Py::Object res(Base::pyCall(py_getSubObjects.ptr(),args.ptr()));
|
||||
if(!res.isTrue())
|
||||
Py::Object res(Base::pyCall(py_getSubObjects.ptr(), args.ptr()));
|
||||
if (!res.isTrue()) {
|
||||
return true;
|
||||
if(!res.isSequence())
|
||||
}
|
||||
if (!res.isSequence()) {
|
||||
throw Py::TypeError("getSubObjects expects return type of tuple");
|
||||
}
|
||||
Py::Sequence seq(res);
|
||||
for(Py_ssize_t i=0;i<seq.length();++i) {
|
||||
for (Py_ssize_t i = 0; i < seq.length(); ++i) {
|
||||
Py::Object name(seq[i].ptr());
|
||||
if(!name.isString())
|
||||
if (!name.isString()) {
|
||||
throw Py::TypeError("getSubObjects expects string in returned sequence");
|
||||
}
|
||||
ret.push_back(name.as_string());
|
||||
}
|
||||
return true;
|
||||
@@ -340,48 +366,56 @@ bool FeaturePythonImp::getSubObjects(std::vector<std::string> &ret, int reason)
|
||||
PyErr_Clear();
|
||||
return false;
|
||||
}
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool FeaturePythonImp::getLinkedObject(DocumentObject *&ret, bool recurse,
|
||||
Base::Matrix4D *_mat, bool transform, int depth) const
|
||||
bool FeaturePythonImp::getLinkedObject(DocumentObject*& ret,
|
||||
bool recurse,
|
||||
Base::Matrix4D* _mat,
|
||||
bool transform,
|
||||
int depth) const
|
||||
{
|
||||
FC_PY_CALL_CHECK(getLinkedObject);
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::Tuple args(5);
|
||||
args.setItem(0, Py::Object(object->getPyObject(), true));
|
||||
args.setItem(1,Py::Boolean(recurse));
|
||||
Base::MatrixPy *pyMat = new Base::MatrixPy(new Base::Matrix4D);
|
||||
if(_mat) *pyMat->getMatrixPtr() = *_mat;
|
||||
args.setItem(2,Py::asObject(pyMat));
|
||||
args.setItem(3,Py::Boolean(transform));
|
||||
args.setItem(4,Py::Int(depth));
|
||||
args.setItem(1, Py::Boolean(recurse));
|
||||
Base::MatrixPy* pyMat = new Base::MatrixPy(new Base::Matrix4D);
|
||||
if (_mat) {
|
||||
*pyMat->getMatrixPtr() = *_mat;
|
||||
}
|
||||
args.setItem(2, Py::asObject(pyMat));
|
||||
args.setItem(3, Py::Boolean(transform));
|
||||
args.setItem(4, Py::Int(depth));
|
||||
|
||||
Py::Object res(Base::pyCall(py_getLinkedObject.ptr(),args.ptr()));
|
||||
if(!res.isTrue()) {
|
||||
Py::Object res(Base::pyCall(py_getLinkedObject.ptr(), args.ptr()));
|
||||
if (!res.isTrue()) {
|
||||
ret = object;
|
||||
return true;
|
||||
}
|
||||
if(!res.isSequence())
|
||||
throw Py::TypeError("getLinkedObject expects return type of (object,matrix)");
|
||||
Py::Sequence seq(res);
|
||||
if(seq.length() != 2 ||
|
||||
(!seq.getItem(0).isNone() &&
|
||||
!PyObject_TypeCheck(seq.getItem(0).ptr(),&DocumentObjectPy::Type)) ||
|
||||
!PyObject_TypeCheck(seq.getItem(1).ptr(),&Base::MatrixPy::Type))
|
||||
{
|
||||
if (!res.isSequence()) {
|
||||
throw Py::TypeError("getLinkedObject expects return type of (object,matrix)");
|
||||
}
|
||||
if(_mat)
|
||||
Py::Sequence seq(res);
|
||||
if (seq.length() != 2
|
||||
|| (!seq.getItem(0).isNone()
|
||||
&& !PyObject_TypeCheck(seq.getItem(0).ptr(), &DocumentObjectPy::Type))
|
||||
|| !PyObject_TypeCheck(seq.getItem(1).ptr(), &Base::MatrixPy::Type)) {
|
||||
throw Py::TypeError("getLinkedObject expects return type of (object,matrix)");
|
||||
}
|
||||
if (_mat) {
|
||||
*_mat = *static_cast<Base::MatrixPy*>(seq.getItem(1).ptr())->getMatrixPtr();
|
||||
if(seq.getItem(0).isNone())
|
||||
}
|
||||
if (seq.getItem(0).isNone()) {
|
||||
ret = object;
|
||||
else
|
||||
}
|
||||
else {
|
||||
ret = static_cast<DocumentObjectPy*>(seq.getItem(0).ptr())->getDocumentObjectPtr();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
@@ -389,28 +423,27 @@ bool FeaturePythonImp::getLinkedObject(DocumentObject *&ret, bool recurse,
|
||||
PyErr_Clear();
|
||||
return false;
|
||||
}
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
ret = nullptr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *FeaturePythonImp::getPyObject()
|
||||
PyObject* FeaturePythonImp::getPyObject()
|
||||
{
|
||||
// ref counter is set to 1
|
||||
return new FeaturePythonPyT<DocumentObjectPy>(object);
|
||||
}
|
||||
|
||||
FeaturePythonImp::ValueT
|
||||
FeaturePythonImp::hasChildElement() const
|
||||
FeaturePythonImp::ValueT FeaturePythonImp::hasChildElement() const
|
||||
{
|
||||
_FC_PY_CALL_CHECK(hasChildElement,return(NotImplemented));
|
||||
_FC_PY_CALL_CHECK(hasChildElement, return (NotImplemented));
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::Object(object->getPyObject(), true));
|
||||
Py::Boolean ok(Base::pyCall(py_hasChildElement.ptr(),args.ptr()));
|
||||
Py::Boolean ok(Base::pyCall(py_hasChildElement.ptr(), args.ptr()));
|
||||
return static_cast<bool>(ok) ? Accepted : Rejected;
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
@@ -419,48 +452,50 @@ FeaturePythonImp::hasChildElement() const
|
||||
return NotImplemented;
|
||||
}
|
||||
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
return Rejected;
|
||||
}
|
||||
}
|
||||
|
||||
int FeaturePythonImp::isElementVisible(const char *element) const {
|
||||
_FC_PY_CALL_CHECK(isElementVisible,return(-2));
|
||||
int FeaturePythonImp::isElementVisible(const char* element) const
|
||||
{
|
||||
_FC_PY_CALL_CHECK(isElementVisible, return (-2));
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::Tuple args(2);
|
||||
args.setItem(0, Py::Object(object->getPyObject(), true));
|
||||
args.setItem(1,Py::String(element?element:""));
|
||||
return Py::Int(Base::pyCall(py_isElementVisible.ptr(),args.ptr()));
|
||||
args.setItem(1, Py::String(element ? element : ""));
|
||||
return Py::Int(Base::pyCall(py_isElementVisible.ptr(), args.ptr()));
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
|
||||
PyErr_Clear();
|
||||
return -2;
|
||||
}
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int FeaturePythonImp::setElementVisible(const char *element, bool visible) {
|
||||
_FC_PY_CALL_CHECK(setElementVisible,return(-2));
|
||||
int FeaturePythonImp::setElementVisible(const char* element, bool visible)
|
||||
{
|
||||
_FC_PY_CALL_CHECK(setElementVisible, return (-2));
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::Tuple args(3);
|
||||
args.setItem(0, Py::Object(object->getPyObject(), true));
|
||||
args.setItem(1,Py::String(element?element:""));
|
||||
args.setItem(2,Py::Boolean(visible));
|
||||
return Py::Int(Base::pyCall(py_setElementVisible.ptr(),args.ptr()));
|
||||
args.setItem(1, Py::String(element ? element : ""));
|
||||
args.setItem(2, Py::Boolean(visible));
|
||||
return Py::Int(Base::pyCall(py_setElementVisible.ptr(), args.ptr()));
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
|
||||
PyErr_Clear();
|
||||
return -2;
|
||||
}
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
return -1;
|
||||
}
|
||||
@@ -468,30 +503,29 @@ int FeaturePythonImp::setElementVisible(const char *element, bool visible) {
|
||||
|
||||
std::string FeaturePythonImp::getViewProviderName()
|
||||
{
|
||||
_FC_PY_CALL_CHECK(getViewProviderName,return(std::string()));
|
||||
_FC_PY_CALL_CHECK(getViewProviderName, return (std::string()));
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::TupleN args(Py::Object(object->getPyObject(), true));
|
||||
Py::String ret(Base::pyCall(py_getViewProviderName.ptr(),args.ptr()));
|
||||
Py::String ret(Base::pyCall(py_getViewProviderName.ptr(), args.ptr()));
|
||||
return ret.as_string();
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
FeaturePythonImp::ValueT
|
||||
FeaturePythonImp::canLinkProperties() const
|
||||
FeaturePythonImp::ValueT FeaturePythonImp::canLinkProperties() const
|
||||
{
|
||||
_FC_PY_CALL_CHECK(canLinkProperties,return(NotImplemented));
|
||||
_FC_PY_CALL_CHECK(canLinkProperties, return (NotImplemented));
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::Object(object->getPyObject(), true));
|
||||
Py::Boolean ok(Base::pyCall(py_canLinkProperties.ptr(),args.ptr()));
|
||||
Py::Boolean ok(Base::pyCall(py_canLinkProperties.ptr(), args.ptr()));
|
||||
return ok ? Accepted : Rejected;
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
@@ -499,21 +533,20 @@ FeaturePythonImp::canLinkProperties() const
|
||||
PyErr_Clear();
|
||||
return NotImplemented;
|
||||
}
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
return Rejected;
|
||||
}
|
||||
}
|
||||
|
||||
FeaturePythonImp::ValueT
|
||||
FeaturePythonImp::allowDuplicateLabel() const
|
||||
FeaturePythonImp::ValueT FeaturePythonImp::allowDuplicateLabel() const
|
||||
{
|
||||
_FC_PY_CALL_CHECK(allowDuplicateLabel,return(NotImplemented));
|
||||
_FC_PY_CALL_CHECK(allowDuplicateLabel, return (NotImplemented));
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::Object(object->getPyObject(), true));
|
||||
Py::Boolean ok(Base::pyCall(py_allowDuplicateLabel.ptr(),args.ptr()));
|
||||
Py::Boolean ok(Base::pyCall(py_allowDuplicateLabel.ptr(), args.ptr()));
|
||||
return ok ? Accepted : Rejected;
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
@@ -522,19 +555,20 @@ FeaturePythonImp::allowDuplicateLabel() const
|
||||
return NotImplemented;
|
||||
}
|
||||
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
return Rejected;
|
||||
}
|
||||
}
|
||||
|
||||
int FeaturePythonImp::canLoadPartial() const {
|
||||
_FC_PY_CALL_CHECK(canLoadPartial,return(-1));
|
||||
int FeaturePythonImp::canLoadPartial() const
|
||||
{
|
||||
_FC_PY_CALL_CHECK(canLoadPartial, return (-1));
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::Object(object->getPyObject(), true));
|
||||
Py::Int ret(Base::pyCall(py_canLoadPartial.ptr(),args.ptr()));
|
||||
Py::Int ret(Base::pyCall(py_canLoadPartial.ptr(), args.ptr()));
|
||||
return ret;
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
@@ -542,28 +576,28 @@ int FeaturePythonImp::canLoadPartial() const {
|
||||
PyErr_Clear();
|
||||
return -1;
|
||||
}
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
FeaturePythonImp::ValueT
|
||||
FeaturePythonImp::redirectSubName(std::ostringstream &ss,
|
||||
App::DocumentObject *topParent,
|
||||
App::DocumentObject *child) const
|
||||
FeaturePythonImp::ValueT FeaturePythonImp::redirectSubName(std::ostringstream& ss,
|
||||
App::DocumentObject* topParent,
|
||||
App::DocumentObject* child) const
|
||||
{
|
||||
_FC_PY_CALL_CHECK(redirectSubName,return(NotImplemented));
|
||||
_FC_PY_CALL_CHECK(redirectSubName, return (NotImplemented));
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::Tuple args(4);
|
||||
args.setItem(0, Py::Object(object->getPyObject(), true));
|
||||
args.setItem(1,Py::String(ss.str()));
|
||||
args.setItem(2,topParent?Py::Object(topParent->getPyObject(),true):Py::Object());
|
||||
args.setItem(3,child?Py::Object(child->getPyObject(),true):Py::Object());
|
||||
Py::Object ret(Base::pyCall(py_redirectSubName.ptr(),args.ptr()));
|
||||
if (ret.isNone())
|
||||
args.setItem(1, Py::String(ss.str()));
|
||||
args.setItem(2, topParent ? Py::Object(topParent->getPyObject(), true) : Py::Object());
|
||||
args.setItem(3, child ? Py::Object(child->getPyObject(), true) : Py::Object());
|
||||
Py::Object ret(Base::pyCall(py_redirectSubName.ptr(), args.ptr()));
|
||||
if (ret.isNone()) {
|
||||
return Rejected;
|
||||
}
|
||||
ss.str("");
|
||||
ss << ret.as_string();
|
||||
return Accepted;
|
||||
@@ -574,20 +608,20 @@ FeaturePythonImp::redirectSubName(std::ostringstream &ss,
|
||||
return NotImplemented;
|
||||
}
|
||||
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
return Rejected;
|
||||
}
|
||||
}
|
||||
|
||||
bool FeaturePythonImp::editProperty(const char *name)
|
||||
bool FeaturePythonImp::editProperty(const char* name)
|
||||
{
|
||||
_FC_PY_CALL_CHECK(editProperty,return false);
|
||||
_FC_PY_CALL_CHECK(editProperty, return false);
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, Py::String(name));
|
||||
Py::Object ret(Base::pyCall(py_editProperty.ptr(),args.ptr()));
|
||||
Py::Object ret(Base::pyCall(py_editProperty.ptr(), args.ptr()));
|
||||
return ret.isTrue();
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
@@ -596,7 +630,7 @@ bool FeaturePythonImp::editProperty(const char *name)
|
||||
return false;
|
||||
}
|
||||
|
||||
Base::PyException e; // extract the Python error text
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
return false;
|
||||
@@ -604,29 +638,37 @@ bool FeaturePythonImp::editProperty(const char *name)
|
||||
|
||||
// ---------------------------------------------------------
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
PROPERTY_SOURCE_TEMPLATE(App::FeaturePython, App::DocumentObject)
|
||||
template<> const char* App::FeaturePython::getViewProviderName() const {
|
||||
template<>
|
||||
const char* App::FeaturePython::getViewProviderName() const
|
||||
{
|
||||
return "Gui::ViewProviderFeaturePython";
|
||||
}
|
||||
template<> PyObject* App::FeaturePython::getPyObject() {
|
||||
template<>
|
||||
PyObject* App::FeaturePython::getPyObject()
|
||||
{
|
||||
if (PythonObject.is(Py::_None())) {
|
||||
// ref counter is set to 1
|
||||
PythonObject = Py::Object(new FeaturePythonPyT<DocumentObjectPy>(this),true);
|
||||
PythonObject = Py::Object(new FeaturePythonPyT<DocumentObjectPy>(this), true);
|
||||
}
|
||||
return Py::new_reference_to(PythonObject);
|
||||
}
|
||||
// explicit template instantiation
|
||||
template class AppExport FeaturePythonT<DocumentObject>;
|
||||
}
|
||||
} // namespace App
|
||||
|
||||
// ---------------------------------------------------------
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
PROPERTY_SOURCE_TEMPLATE(App::GeometryPython, App::GeoFeature)
|
||||
template<> const char* App::GeometryPython::getViewProviderName() const {
|
||||
template<>
|
||||
const char* App::GeometryPython::getViewProviderName() const
|
||||
{
|
||||
return "Gui::ViewProviderGeometryPython";
|
||||
}
|
||||
// explicit template instantiation
|
||||
template class AppExport FeaturePythonT<GeoFeature>;
|
||||
}
|
||||
} // namespace App
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef APP_FEATUREPYTHON_H
|
||||
#define APP_FEATUREPYTHON_H
|
||||
|
||||
@@ -38,10 +37,11 @@ class Property;
|
||||
class AppExport FeaturePythonImp
|
||||
{
|
||||
public:
|
||||
enum ValueT {
|
||||
NotImplemented = 0, // not handled
|
||||
Accepted = 1, // handled and accepted
|
||||
Rejected = 2 // handled and rejected
|
||||
enum ValueT
|
||||
{
|
||||
NotImplemented = 0, // not handled
|
||||
Accepted = 1, // handled and accepted
|
||||
Rejected = 2 // handled and rejected
|
||||
};
|
||||
|
||||
explicit FeaturePythonImp(App::DocumentObject*);
|
||||
@@ -50,93 +50,95 @@ public:
|
||||
bool execute();
|
||||
bool mustExecute() const;
|
||||
void onBeforeChange(const Property* prop);
|
||||
bool onBeforeChangeLabel(std::string &newLabel);
|
||||
bool onBeforeChangeLabel(std::string& newLabel);
|
||||
void onChanged(const Property* prop);
|
||||
void onDocumentRestored();
|
||||
void unsetupObject();
|
||||
std::string getViewProviderName();
|
||||
PyObject *getPyObject();
|
||||
PyObject* getPyObject();
|
||||
|
||||
bool getSubObject(App::DocumentObject *&ret, const char *subname, PyObject **pyObj,
|
||||
Base::Matrix4D *mat, bool transform, int depth) const;
|
||||
bool getSubObject(App::DocumentObject*& ret,
|
||||
const char* subname,
|
||||
PyObject** pyObj,
|
||||
Base::Matrix4D* mat,
|
||||
bool transform,
|
||||
int depth) const;
|
||||
|
||||
bool getSubObjects(std::vector<std::string> &ret, int reason) const;
|
||||
bool getSubObjects(std::vector<std::string>& ret, int reason) const;
|
||||
|
||||
bool getLinkedObject(App::DocumentObject *&ret, bool recurse,
|
||||
Base::Matrix4D *mat, bool transform, int depth) const;
|
||||
bool getLinkedObject(App::DocumentObject*& ret,
|
||||
bool recurse,
|
||||
Base::Matrix4D* mat,
|
||||
bool transform,
|
||||
int depth) const;
|
||||
|
||||
ValueT canLinkProperties() const;
|
||||
|
||||
ValueT allowDuplicateLabel() const;
|
||||
|
||||
ValueT redirectSubName(std::ostringstream &ss,
|
||||
App::DocumentObject *topParent,
|
||||
App::DocumentObject *child) const;
|
||||
ValueT redirectSubName(std::ostringstream& ss,
|
||||
App::DocumentObject* topParent,
|
||||
App::DocumentObject* child) const;
|
||||
|
||||
int canLoadPartial() const;
|
||||
|
||||
/// return true to activate tree view group object handling
|
||||
ValueT hasChildElement() const;
|
||||
/// Get sub-element visibility
|
||||
int isElementVisible(const char *) const;
|
||||
int isElementVisible(const char*) const;
|
||||
/// Set sub-element visibility
|
||||
int setElementVisible(const char *, bool);
|
||||
int setElementVisible(const char*, bool);
|
||||
|
||||
bool editProperty(const char *propName);
|
||||
bool editProperty(const char* propName);
|
||||
|
||||
private:
|
||||
App::DocumentObject* object;
|
||||
bool has__object__{false};
|
||||
bool has__object__ {false};
|
||||
|
||||
#define FC_PY_FEATURE_PYTHON \
|
||||
FC_PY_ELEMENT(execute)\
|
||||
FC_PY_ELEMENT(mustExecute)\
|
||||
FC_PY_ELEMENT(onBeforeChange)\
|
||||
FC_PY_ELEMENT(onBeforeChangeLabel)\
|
||||
FC_PY_ELEMENT(onChanged)\
|
||||
FC_PY_ELEMENT(onDocumentRestored)\
|
||||
FC_PY_ELEMENT(unsetupObject)\
|
||||
FC_PY_ELEMENT(getViewProviderName)\
|
||||
FC_PY_ELEMENT(getSubObject)\
|
||||
FC_PY_ELEMENT(getSubObjects)\
|
||||
FC_PY_ELEMENT(getLinkedObject)\
|
||||
FC_PY_ELEMENT(canLinkProperties)\
|
||||
FC_PY_ELEMENT(allowDuplicateLabel)\
|
||||
FC_PY_ELEMENT(redirectSubName)\
|
||||
FC_PY_ELEMENT(canLoadPartial)\
|
||||
FC_PY_ELEMENT(hasChildElement)\
|
||||
FC_PY_ELEMENT(isElementVisible)\
|
||||
FC_PY_ELEMENT(setElementVisible)\
|
||||
FC_PY_ELEMENT(editProperty)\
|
||||
#define FC_PY_FEATURE_PYTHON \
|
||||
FC_PY_ELEMENT(execute) \
|
||||
FC_PY_ELEMENT(mustExecute) \
|
||||
FC_PY_ELEMENT(onBeforeChange) \
|
||||
FC_PY_ELEMENT(onBeforeChangeLabel) \
|
||||
FC_PY_ELEMENT(onChanged) \
|
||||
FC_PY_ELEMENT(onDocumentRestored) \
|
||||
FC_PY_ELEMENT(unsetupObject) \
|
||||
FC_PY_ELEMENT(getViewProviderName) \
|
||||
FC_PY_ELEMENT(getSubObject) \
|
||||
FC_PY_ELEMENT(getSubObjects) \
|
||||
FC_PY_ELEMENT(getLinkedObject) \
|
||||
FC_PY_ELEMENT(canLinkProperties) \
|
||||
FC_PY_ELEMENT(allowDuplicateLabel) \
|
||||
FC_PY_ELEMENT(redirectSubName) \
|
||||
FC_PY_ELEMENT(canLoadPartial) \
|
||||
FC_PY_ELEMENT(hasChildElement) \
|
||||
FC_PY_ELEMENT(isElementVisible) \
|
||||
FC_PY_ELEMENT(setElementVisible) \
|
||||
FC_PY_ELEMENT(editProperty)
|
||||
|
||||
#define FC_PY_ELEMENT_DEFINE(_name) \
|
||||
Py::Object py_##_name;
|
||||
#define FC_PY_ELEMENT_DEFINE(_name) Py::Object py_##_name;
|
||||
|
||||
#define FC_PY_ELEMENT_INIT(_name) \
|
||||
FC_PY_GetCallable(pyobj,#_name,py_##_name);\
|
||||
if(!py_##_name.isNone()) {\
|
||||
PyObject *pyRecursive = PyObject_GetAttrString(pyobj, \
|
||||
"__allow_recursive_" #_name);\
|
||||
if(!pyRecursive) {\
|
||||
PyErr_Clear();\
|
||||
_Flags.set(FlagAllowRecursive_##_name, false);\
|
||||
}else{\
|
||||
_Flags.set(FlagAllowRecursive_##_name, PyObject_IsTrue(pyRecursive));\
|
||||
Py_DECREF(pyRecursive);\
|
||||
}\
|
||||
#define FC_PY_ELEMENT_INIT(_name) \
|
||||
FC_PY_GetCallable(pyobj, #_name, py_##_name); \
|
||||
if (!py_##_name.isNone()) { \
|
||||
PyObject* pyRecursive = PyObject_GetAttrString(pyobj, "__allow_recursive_" #_name); \
|
||||
if (!pyRecursive) { \
|
||||
PyErr_Clear(); \
|
||||
_Flags.set(FlagAllowRecursive_##_name, false); \
|
||||
} \
|
||||
else { \
|
||||
_Flags.set(FlagAllowRecursive_##_name, PyObject_IsTrue(pyRecursive)); \
|
||||
Py_DECREF(pyRecursive); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FC_PY_ELEMENT_FLAG(_name) \
|
||||
FlagCalling_##_name,\
|
||||
FlagAllowRecursive_##_name,
|
||||
#define FC_PY_ELEMENT_FLAG(_name) FlagCalling_##_name, FlagAllowRecursive_##_name,
|
||||
|
||||
#define _FC_PY_CALL_CHECK(_name,_ret) \
|
||||
if((!_Flags.test(FlagAllowRecursive_##_name) \
|
||||
&& _Flags.test(FlagCalling_##_name)) \
|
||||
|| py_##_name.isNone()) \
|
||||
{\
|
||||
_ret;\
|
||||
}\
|
||||
#define _FC_PY_CALL_CHECK(_name, _ret) \
|
||||
if ((!_Flags.test(FlagAllowRecursive_##_name) && _Flags.test(FlagCalling_##_name)) \
|
||||
|| py_##_name.isNone()) { \
|
||||
_ret; \
|
||||
} \
|
||||
Base::BitsetLocker<Flags> guard(_Flags, FlagCalling_##_name);
|
||||
|
||||
#undef FC_PY_ELEMENT
|
||||
@@ -147,16 +149,16 @@ private:
|
||||
#undef FC_PY_ELEMENT
|
||||
#define FC_PY_ELEMENT(_name) FC_PY_ELEMENT_FLAG(_name)
|
||||
|
||||
enum Flag {
|
||||
FC_PY_FEATURE_PYTHON
|
||||
FlagMax,
|
||||
enum Flag
|
||||
{
|
||||
FC_PY_FEATURE_PYTHON FlagMax,
|
||||
};
|
||||
|
||||
using Flags = std::bitset<FlagMax>;
|
||||
mutable Flags _Flags;
|
||||
|
||||
public:
|
||||
void init(PyObject *pyobj);
|
||||
void init(PyObject* pyobj);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -164,185 +166,226 @@ public:
|
||||
* derived class as Python feature -- simply by subclassing.
|
||||
* @author Werner Mayer
|
||||
*/
|
||||
template <class FeatureT>
|
||||
class FeaturePythonT : public FeatureT
|
||||
template<class FeatureT>
|
||||
class FeaturePythonT: public FeatureT
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(App::FeaturePythonT<FeatureT>);
|
||||
|
||||
public:
|
||||
FeaturePythonT() {
|
||||
ADD_PROPERTY(Proxy,(Py::Object()));
|
||||
FeaturePythonT()
|
||||
{
|
||||
ADD_PROPERTY(Proxy, (Py::Object()));
|
||||
// cannot move this to the initializer list to avoid warning
|
||||
imp = new FeaturePythonImp(this);
|
||||
}
|
||||
~FeaturePythonT() override {
|
||||
~FeaturePythonT() override
|
||||
{
|
||||
delete imp;
|
||||
}
|
||||
|
||||
/** @name methods override DocumentObject */
|
||||
//@{
|
||||
short mustExecute() const override {
|
||||
if (this->isTouched())
|
||||
short mustExecute() const override
|
||||
{
|
||||
if (this->isTouched()) {
|
||||
return 1;
|
||||
}
|
||||
auto ret = FeatureT::mustExecute();
|
||||
if(ret) return ret;
|
||||
return imp->mustExecute()?1:0;
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
return imp->mustExecute() ? 1 : 0;
|
||||
}
|
||||
/// recalculate the Feature
|
||||
DocumentObjectExecReturn *execute() override {
|
||||
DocumentObjectExecReturn* execute() override
|
||||
{
|
||||
try {
|
||||
bool handled = imp->execute();
|
||||
if (!handled)
|
||||
if (!handled) {
|
||||
return FeatureT::execute();
|
||||
}
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
return new App::DocumentObjectExecReturn(e.what());
|
||||
}
|
||||
return DocumentObject::StdReturn;
|
||||
}
|
||||
const char* getViewProviderNameOverride() const override {
|
||||
const char* getViewProviderNameOverride() const override
|
||||
{
|
||||
viewProviderName = imp->getViewProviderName();
|
||||
if(!viewProviderName.empty())
|
||||
if (!viewProviderName.empty()) {
|
||||
return viewProviderName.c_str();
|
||||
}
|
||||
return FeatureT::getViewProviderNameOverride();
|
||||
}
|
||||
/// returns the type name of the ViewProvider
|
||||
const char* getViewProviderName() const override {
|
||||
const char* getViewProviderName() const override
|
||||
{
|
||||
return FeatureT::getViewProviderName();
|
||||
}
|
||||
|
||||
App::DocumentObject *getSubObject(const char *subname, PyObject **pyObj,
|
||||
Base::Matrix4D *mat, bool transform, int depth) const override
|
||||
App::DocumentObject* getSubObject(const char* subname,
|
||||
PyObject** pyObj,
|
||||
Base::Matrix4D* mat,
|
||||
bool transform,
|
||||
int depth) const override
|
||||
{
|
||||
App::DocumentObject *ret = nullptr;
|
||||
if(imp->getSubObject(ret,subname,pyObj,mat,transform,depth))
|
||||
App::DocumentObject* ret = nullptr;
|
||||
if (imp->getSubObject(ret, subname, pyObj, mat, transform, depth)) {
|
||||
return ret;
|
||||
return FeatureT::getSubObject(subname,pyObj,mat,transform,depth);
|
||||
}
|
||||
return FeatureT::getSubObject(subname, pyObj, mat, transform, depth);
|
||||
}
|
||||
|
||||
std::vector<std::string> getSubObjects(int reason=0) const override {
|
||||
std::vector<std::string> getSubObjects(int reason = 0) const override
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
if(imp->getSubObjects(ret,reason))
|
||||
if (imp->getSubObjects(ret, reason)) {
|
||||
return ret;
|
||||
}
|
||||
return FeatureT::getSubObjects(reason);
|
||||
}
|
||||
|
||||
App::DocumentObject *getLinkedObject(bool recurse,
|
||||
Base::Matrix4D *mat, bool transform, int depth) const override
|
||||
App::DocumentObject*
|
||||
getLinkedObject(bool recurse, Base::Matrix4D* mat, bool transform, int depth) const override
|
||||
{
|
||||
App::DocumentObject *ret = nullptr;
|
||||
if(imp->getLinkedObject(ret,recurse,mat,transform,depth))
|
||||
App::DocumentObject* ret = nullptr;
|
||||
if (imp->getLinkedObject(ret, recurse, mat, transform, depth)) {
|
||||
return ret;
|
||||
return FeatureT::getLinkedObject(recurse,mat,transform,depth);
|
||||
}
|
||||
return FeatureT::getLinkedObject(recurse, mat, transform, depth);
|
||||
}
|
||||
|
||||
/// return true to activate tree view group object handling
|
||||
bool hasChildElement() const override {
|
||||
bool hasChildElement() const override
|
||||
{
|
||||
switch (imp->hasChildElement()) {
|
||||
case FeaturePythonImp::Accepted:
|
||||
return true;
|
||||
case FeaturePythonImp::Rejected:
|
||||
return false;
|
||||
default:
|
||||
return FeatureT::hasChildElement();
|
||||
case FeaturePythonImp::Accepted:
|
||||
return true;
|
||||
case FeaturePythonImp::Rejected:
|
||||
return false;
|
||||
default:
|
||||
return FeatureT::hasChildElement();
|
||||
}
|
||||
}
|
||||
/// Get sub-element visibility
|
||||
int isElementVisible(const char *element) const override {
|
||||
int isElementVisible(const char* element) const override
|
||||
{
|
||||
int ret = imp->isElementVisible(element);
|
||||
if(ret == -2)
|
||||
if (ret == -2) {
|
||||
return FeatureT::isElementVisible(element);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/// Set sub-element visibility
|
||||
int setElementVisible(const char *element, bool visible) override {
|
||||
int ret = imp->setElementVisible(element,visible);
|
||||
if(ret == -2)
|
||||
return FeatureT::setElementVisible(element,visible);
|
||||
int setElementVisible(const char* element, bool visible) override
|
||||
{
|
||||
int ret = imp->setElementVisible(element, visible);
|
||||
if (ret == -2) {
|
||||
return FeatureT::setElementVisible(element, visible);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool canLinkProperties() const override {
|
||||
switch (imp->canLinkProperties()) {
|
||||
case FeaturePythonImp::Accepted:
|
||||
return true;
|
||||
case FeaturePythonImp::Rejected:
|
||||
return false;
|
||||
default:
|
||||
return FeatureT::canLinkProperties();
|
||||
}
|
||||
}
|
||||
|
||||
bool allowDuplicateLabel() const override {
|
||||
switch (imp->allowDuplicateLabel()) {
|
||||
case FeaturePythonImp::Accepted:
|
||||
return true;
|
||||
case FeaturePythonImp::Rejected:
|
||||
return false;
|
||||
default:
|
||||
return FeatureT::allowDuplicateLabel();
|
||||
}
|
||||
}
|
||||
|
||||
bool redirectSubName(std::ostringstream &ss,
|
||||
App::DocumentObject *topParent, App::DocumentObject *child) const override
|
||||
bool canLinkProperties() const override
|
||||
{
|
||||
switch (imp->redirectSubName(ss,topParent,child)) {
|
||||
case FeaturePythonImp::Accepted:
|
||||
return true;
|
||||
case FeaturePythonImp::Rejected:
|
||||
return false;
|
||||
default:
|
||||
return FeatureT::redirectSubName(ss, topParent, child);
|
||||
switch (imp->canLinkProperties()) {
|
||||
case FeaturePythonImp::Accepted:
|
||||
return true;
|
||||
case FeaturePythonImp::Rejected:
|
||||
return false;
|
||||
default:
|
||||
return FeatureT::canLinkProperties();
|
||||
}
|
||||
}
|
||||
|
||||
int canLoadPartial() const override {
|
||||
bool allowDuplicateLabel() const override
|
||||
{
|
||||
switch (imp->allowDuplicateLabel()) {
|
||||
case FeaturePythonImp::Accepted:
|
||||
return true;
|
||||
case FeaturePythonImp::Rejected:
|
||||
return false;
|
||||
default:
|
||||
return FeatureT::allowDuplicateLabel();
|
||||
}
|
||||
}
|
||||
|
||||
bool redirectSubName(std::ostringstream& ss,
|
||||
App::DocumentObject* topParent,
|
||||
App::DocumentObject* child) const override
|
||||
{
|
||||
switch (imp->redirectSubName(ss, topParent, child)) {
|
||||
case FeaturePythonImp::Accepted:
|
||||
return true;
|
||||
case FeaturePythonImp::Rejected:
|
||||
return false;
|
||||
default:
|
||||
return FeatureT::redirectSubName(ss, topParent, child);
|
||||
}
|
||||
}
|
||||
|
||||
int canLoadPartial() const override
|
||||
{
|
||||
int ret = imp->canLoadPartial();
|
||||
if(ret>=0)
|
||||
if (ret >= 0) {
|
||||
return ret;
|
||||
}
|
||||
return FeatureT::canLoadPartial();
|
||||
}
|
||||
|
||||
void editProperty(const char *propName) override {
|
||||
if (!imp->editProperty(propName))
|
||||
void editProperty(const char* propName) override
|
||||
{
|
||||
if (!imp->editProperty(propName)) {
|
||||
FeatureT::editProperty(propName);
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *getPyObject() override {
|
||||
PyObject* getPyObject() override
|
||||
{
|
||||
if (FeatureT::PythonObject.is(Py::_None())) {
|
||||
// ref counter is set to 1
|
||||
FeatureT::PythonObject = Py::Object(imp->getPyObject(),true);
|
||||
FeatureT::PythonObject = Py::Object(imp->getPyObject(), true);
|
||||
}
|
||||
return Py::new_reference_to(FeatureT::PythonObject);
|
||||
}
|
||||
void setPyObject(PyObject *obj) override {
|
||||
if (obj)
|
||||
void setPyObject(PyObject* obj) override
|
||||
{
|
||||
if (obj) {
|
||||
FeatureT::PythonObject = obj;
|
||||
else
|
||||
}
|
||||
else {
|
||||
FeatureT::PythonObject = Py::None();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void onBeforeChange(const Property* prop) override {
|
||||
void onBeforeChange(const Property* prop) override
|
||||
{
|
||||
FeatureT::onBeforeChange(prop);
|
||||
imp->onBeforeChange(prop);
|
||||
}
|
||||
void onBeforeChangeLabel(std::string &newLabel) override{
|
||||
if(!imp->onBeforeChangeLabel(newLabel))
|
||||
void onBeforeChangeLabel(std::string& newLabel) override
|
||||
{
|
||||
if (!imp->onBeforeChangeLabel(newLabel)) {
|
||||
FeatureT::onBeforeChangeLabel(newLabel);
|
||||
}
|
||||
}
|
||||
void onChanged(const Property* prop) override {
|
||||
if(prop == &Proxy)
|
||||
void onChanged(const Property* prop) override
|
||||
{
|
||||
if (prop == &Proxy) {
|
||||
imp->init(Proxy.getValue().ptr());
|
||||
}
|
||||
imp->onChanged(prop);
|
||||
FeatureT::onChanged(prop);
|
||||
}
|
||||
void onDocumentRestored() override {
|
||||
void onDocumentRestored() override
|
||||
{
|
||||
imp->onDocumentRestored();
|
||||
FeatureT::onDocumentRestored();
|
||||
}
|
||||
void unsetupObject() override {
|
||||
void unsetupObject() override
|
||||
{
|
||||
imp->unsetupObject();
|
||||
FeatureT::unsetupObject();
|
||||
}
|
||||
@@ -350,8 +393,8 @@ protected:
|
||||
public:
|
||||
FeaturePythonT(const FeaturePythonT&) = delete;
|
||||
FeaturePythonT(FeaturePythonT&&) = delete;
|
||||
FeaturePythonT& operator= (const FeaturePythonT&) = delete;
|
||||
FeaturePythonT& operator= (FeaturePythonT&&) = delete;
|
||||
FeaturePythonT& operator=(const FeaturePythonT&) = delete;
|
||||
FeaturePythonT& operator=(FeaturePythonT&&) = delete;
|
||||
|
||||
private:
|
||||
FeaturePythonImp* imp;
|
||||
@@ -360,9 +403,9 @@ private:
|
||||
};
|
||||
|
||||
// Special Feature-Python classes
|
||||
using FeaturePython = FeaturePythonT<DocumentObject>;
|
||||
using GeometryPython = FeaturePythonT<GeoFeature >;
|
||||
using FeaturePython = FeaturePythonT<DocumentObject>;
|
||||
using GeometryPython = FeaturePythonT<GeoFeature>;
|
||||
|
||||
} //namespace App
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_FEATUREPYTHON_H
|
||||
#endif // APP_FEATUREPYTHON_H
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
#***************************************************************************
|
||||
#* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
|
||||
#* *
|
||||
#* This file is part of the FreeCAD CAx development system. *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* FreeCAD is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Lesser General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with FreeCAD; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************/
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * FreeCAD is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Lesser General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with FreeCAD; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************/
|
||||
|
||||
# FreeCAD test module
|
||||
#
|
||||
@@ -27,8 +27,7 @@
|
||||
# (if existing) the test function of the modules
|
||||
|
||||
|
||||
|
||||
Log ("FreeCAD test running...\n\n")
|
||||
Log("FreeCAD test running...\n\n")
|
||||
|
||||
import sys
|
||||
|
||||
@@ -39,6 +38,6 @@ testCase = FreeCAD.ConfigGet("TestCase")
|
||||
|
||||
testResult = TestApp.TestText(testCase)
|
||||
|
||||
Log ("FreeCAD test done\n")
|
||||
Log("FreeCAD test done\n")
|
||||
|
||||
sys.exit(0 if testResult.wasSuccessful() else 1)
|
||||
|
||||
@@ -52,24 +52,28 @@ GeoFeatureGroupExtension::GeoFeatureGroupExtension()
|
||||
|
||||
GeoFeatureGroupExtension::~GeoFeatureGroupExtension() = default;
|
||||
|
||||
void GeoFeatureGroupExtension::initExtension(ExtensionContainer* obj) {
|
||||
void GeoFeatureGroupExtension::initExtension(ExtensionContainer* obj)
|
||||
{
|
||||
|
||||
if(!obj->isDerivedFrom(App::GeoFeature::getClassTypeId()))
|
||||
if (!obj->isDerivedFrom(App::GeoFeature::getClassTypeId())) {
|
||||
throw Base::RuntimeError("GeoFeatureGroupExtension can only be applied to GeoFeatures");
|
||||
}
|
||||
|
||||
App::GroupExtension::initExtension(obj);
|
||||
}
|
||||
|
||||
PropertyPlacement& GeoFeatureGroupExtension::placement() {
|
||||
PropertyPlacement& GeoFeatureGroupExtension::placement()
|
||||
{
|
||||
|
||||
if(!getExtendedContainer())
|
||||
if (!getExtendedContainer()) {
|
||||
throw Base::RuntimeError("GeoFeatureGroupExtension was not applied to GeoFeature");
|
||||
}
|
||||
|
||||
return static_cast<App::GeoFeature*>(getExtendedContainer())->Placement;
|
||||
}
|
||||
|
||||
|
||||
void GeoFeatureGroupExtension::transformPlacement(const Base::Placement &transform)
|
||||
void GeoFeatureGroupExtension::transformPlacement(const Base::Placement& transform)
|
||||
{
|
||||
// NOTE: Keep in sync with APP::GeoFeature
|
||||
Base::Placement plm = this->placement().getValue();
|
||||
@@ -79,25 +83,29 @@ void GeoFeatureGroupExtension::transformPlacement(const Base::Placement &transfo
|
||||
|
||||
DocumentObject* GeoFeatureGroupExtension::getGroupOfObject(const DocumentObject* obj)
|
||||
{
|
||||
if(!obj)
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//we will find origins, but not origin features
|
||||
if(obj->isDerivedFrom(App::OriginFeature::getClassTypeId()))
|
||||
// we will find origins, but not origin features
|
||||
if (obj->isDerivedFrom(App::OriginFeature::getClassTypeId())) {
|
||||
return OriginGroupExtension::getGroupOfObject(obj);
|
||||
}
|
||||
|
||||
//compared to GroupExtension we do return here all GeoFeatureGroups including all extensions derived from it
|
||||
//like OriginGroup. That is needed as we use this function to get all local coordinate systems. Also there
|
||||
//is no reason to distinguish between GeoFeatuerGroups, there is only between group/geofeaturegroup
|
||||
// compared to GroupExtension we do return here all GeoFeatureGroups including all extensions
|
||||
// derived from it like OriginGroup. That is needed as we use this function to get all local
|
||||
// coordinate systems. Also there is no reason to distinguish between GeoFeatuerGroups, there is
|
||||
// only between group/geofeaturegroup
|
||||
auto list = obj->getInList();
|
||||
for (auto inObj : list) {
|
||||
|
||||
//There is a chance that a derived geofeaturegroup links with a local link and hence is not
|
||||
//the parent group even though it links to the object. We use hasObject as one and only truth
|
||||
//if it has the object within the group
|
||||
// There is a chance that a derived geofeaturegroup links with a local link and hence is not
|
||||
// the parent group even though it links to the object. We use hasObject as one and only
|
||||
// truth if it has the object within the group
|
||||
auto group = inObj->getExtensionByType<GeoFeatureGroupExtension>(true);
|
||||
if(group && group->hasObject(obj))
|
||||
if (group && group->hasObject(obj)) {
|
||||
return inObj;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -115,8 +123,9 @@ Base::Placement GeoFeatureGroupExtension::globalGroupPlacement()
|
||||
}
|
||||
|
||||
|
||||
Base::Placement GeoFeatureGroupExtension::recursiveGroupPlacement(GeoFeatureGroupExtension* group,
|
||||
std::unordered_set<GeoFeatureGroupExtension*>& history)
|
||||
Base::Placement GeoFeatureGroupExtension::recursiveGroupPlacement(
|
||||
GeoFeatureGroupExtension* group,
|
||||
std::unordered_set<GeoFeatureGroupExtension*>& history)
|
||||
{
|
||||
history.insert(this);
|
||||
|
||||
@@ -135,25 +144,29 @@ Base::Placement GeoFeatureGroupExtension::recursiveGroupPlacement(GeoFeatureGrou
|
||||
return group->placement().getValue();
|
||||
}
|
||||
|
||||
std::vector<DocumentObject*> GeoFeatureGroupExtension::addObjects(std::vector<App::DocumentObject*> objects) {
|
||||
std::vector<DocumentObject*>
|
||||
GeoFeatureGroupExtension::addObjects(std::vector<App::DocumentObject*> objects)
|
||||
{
|
||||
|
||||
std::vector<DocumentObject*> grp = Group.getValues();
|
||||
std::vector<DocumentObject*> ret;
|
||||
|
||||
for(auto object : objects) {
|
||||
for (auto object : objects) {
|
||||
|
||||
if(!allowObject(object))
|
||||
if (!allowObject(object)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//cross CoordinateSystem links are not allowed, so we need to move the whole link group
|
||||
// cross CoordinateSystem links are not allowed, so we need to move the whole link group
|
||||
std::vector<App::DocumentObject*> links = getCSRelevantLinks(object);
|
||||
links.push_back(object);
|
||||
|
||||
for( auto obj : links) {
|
||||
//only one geofeaturegroup per object.
|
||||
auto *group = App::GeoFeatureGroupExtension::getGroupOfObject(obj);
|
||||
if(group && group != getExtendedObject())
|
||||
for (auto obj : links) {
|
||||
// only one geofeaturegroup per object.
|
||||
auto* group = App::GeoFeatureGroupExtension::getGroupOfObject(obj);
|
||||
if (group && group != getExtendedObject()) {
|
||||
group->getExtensionByType<App::GroupExtension>()->removeObject(obj);
|
||||
}
|
||||
|
||||
if (!hasObject(obj)) {
|
||||
grp.push_back(obj);
|
||||
@@ -166,61 +179,68 @@ std::vector<DocumentObject*> GeoFeatureGroupExtension::addObjects(std::vector<Ap
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<DocumentObject*> GeoFeatureGroupExtension::removeObjects(std::vector<App::DocumentObject*> objects) {
|
||||
std::vector<DocumentObject*>
|
||||
GeoFeatureGroupExtension::removeObjects(std::vector<App::DocumentObject*> objects)
|
||||
{
|
||||
|
||||
std::vector<DocumentObject*> removed;
|
||||
std::vector<DocumentObject*> grp = Group.getValues();
|
||||
|
||||
for(auto object : objects) {
|
||||
//cross CoordinateSystem links are not allowed, so we need to remove the whole link group
|
||||
std::vector< DocumentObject* > links = getCSRelevantLinks(object);
|
||||
for (auto object : objects) {
|
||||
// cross CoordinateSystem links are not allowed, so we need to remove the whole link group
|
||||
std::vector<DocumentObject*> links = getCSRelevantLinks(object);
|
||||
links.push_back(object);
|
||||
|
||||
//remove all links out of group
|
||||
for(auto link : links) {
|
||||
// remove all links out of group
|
||||
for (auto link : links) {
|
||||
auto end = std::remove(grp.begin(), grp.end(), link);
|
||||
if(end != grp.end()) {
|
||||
if (end != grp.end()) {
|
||||
grp.erase(end, grp.end());
|
||||
removed.push_back(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!removed.empty())
|
||||
if (!removed.empty()) {
|
||||
Group.setValues(grp);
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
void GeoFeatureGroupExtension::extensionOnChanged(const Property* p) {
|
||||
void GeoFeatureGroupExtension::extensionOnChanged(const Property* p)
|
||||
{
|
||||
|
||||
//objects are only allowed in a single GeoFeatureGroup
|
||||
if(p == &Group && !Group.testStatus(Property::User3)) {
|
||||
// objects are only allowed in a single GeoFeatureGroup
|
||||
if (p == &Group && !Group.testStatus(Property::User3)) {
|
||||
|
||||
if((!getExtendedObject()->isRestoring()
|
||||
|| getExtendedObject()->getDocument()->testStatus(Document::Importing))
|
||||
if ((!getExtendedObject()->isRestoring()
|
||||
|| getExtendedObject()->getDocument()->testStatus(Document::Importing))
|
||||
&& !getExtendedObject()->getDocument()->isPerformingTransaction()) {
|
||||
|
||||
bool error = false;
|
||||
auto corrected = Group.getValues();
|
||||
for(auto obj : Group.getValues()) {
|
||||
for (auto obj : Group.getValues()) {
|
||||
|
||||
//we have already set the obj into the group, so in a case of multiple groups getGroupOfObject
|
||||
//would return anyone of it and hence it is possible that we miss an error. We need a custom check
|
||||
// we have already set the obj into the group, so in a case of multiple groups
|
||||
// getGroupOfObject would return anyone of it and hence it is possible that we miss
|
||||
// an error. We need a custom check
|
||||
auto list = obj->getInList();
|
||||
for (auto in : list) {
|
||||
if(in == getExtendedObject())
|
||||
if (in == getExtendedObject()) {
|
||||
continue;
|
||||
}
|
||||
auto parent = in->getExtensionByType<GeoFeatureGroupExtension>(true);
|
||||
if(parent && parent->hasObject(obj)) {
|
||||
if (parent && parent->hasObject(obj)) {
|
||||
error = true;
|
||||
corrected.erase(std::remove(corrected.begin(), corrected.end(), obj), corrected.end());
|
||||
corrected.erase(std::remove(corrected.begin(), corrected.end(), obj),
|
||||
corrected.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if an error was found we need to correct the values and inform the user
|
||||
if(error) {
|
||||
// if an error was found we need to correct the values and inform the user
|
||||
if (error) {
|
||||
Base::ObjectStatusLocker<Property::Status, Property> guard(Property::User3, &Group);
|
||||
Group.setValues(corrected);
|
||||
throw Base::RuntimeError("Object can only be in a single GeoFeatureGroup");
|
||||
@@ -232,99 +252,119 @@ void GeoFeatureGroupExtension::extensionOnChanged(const Property* p) {
|
||||
}
|
||||
|
||||
|
||||
std::vector< DocumentObject* > GeoFeatureGroupExtension::getScopedObjectsFromLinks(const DocumentObject* obj, LinkScope scope) {
|
||||
std::vector<DocumentObject*>
|
||||
GeoFeatureGroupExtension::getScopedObjectsFromLinks(const DocumentObject* obj, LinkScope scope)
|
||||
{
|
||||
|
||||
if(!obj)
|
||||
if (!obj) {
|
||||
return {};
|
||||
}
|
||||
|
||||
//we get all linked objects. We can't use outList() as this includes the links from expressions
|
||||
std::vector< App::DocumentObject* > result;
|
||||
// we get all linked objects. We can't use outList() as this includes the links from expressions
|
||||
std::vector<App::DocumentObject*> result;
|
||||
std::vector<App::Property*> list;
|
||||
obj->getPropertyList(list);
|
||||
for(App::Property* prop : list) {
|
||||
for (App::Property* prop : list) {
|
||||
auto vec = getScopedObjectsFromLink(prop, scope);
|
||||
result.insert(result.end(), vec.begin(), vec.end());
|
||||
}
|
||||
|
||||
//clear all null objects and duplicates
|
||||
// clear all null objects and duplicates
|
||||
std::sort(result.begin(), result.end());
|
||||
result.erase(std::unique(result.begin(), result.end()), result.end());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector< DocumentObject* > GeoFeatureGroupExtension::getScopedObjectsFromLink(App::Property* prop, LinkScope scope) {
|
||||
std::vector<DocumentObject*> GeoFeatureGroupExtension::getScopedObjectsFromLink(App::Property* prop,
|
||||
LinkScope scope)
|
||||
{
|
||||
|
||||
if(!prop)
|
||||
if (!prop) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector< App::DocumentObject* > result;
|
||||
std::vector<App::DocumentObject*> result;
|
||||
auto link = Base::freecad_dynamic_cast<PropertyLinkBase>(prop);
|
||||
if(link && link->getScope()==scope)
|
||||
if (link && link->getScope() == scope) {
|
||||
link->getLinks(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void GeoFeatureGroupExtension::getCSOutList(const App::DocumentObject* obj,
|
||||
std::vector< DocumentObject* >& vec) {
|
||||
std::vector<DocumentObject*>& vec)
|
||||
{
|
||||
|
||||
if(!obj)
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
//we get all relevant linked objects. We can't use outList() as this includes the links from expressions,
|
||||
//also we only want links with scope Local
|
||||
// we get all relevant linked objects. We can't use outList() as this includes the links from
|
||||
// expressions, also we only want links with scope Local
|
||||
auto result = getScopedObjectsFromLinks(obj, LinkScope::Local);
|
||||
|
||||
//we remove all links to origin features and origins, they belong to a CS too and can't be moved
|
||||
result.erase(std::remove_if(result.begin(), result.end(), [](App::DocumentObject* obj)->bool {
|
||||
return (obj->isDerivedFrom(App::OriginFeature::getClassTypeId()) ||
|
||||
obj->isDerivedFrom(App::Origin::getClassTypeId()));
|
||||
}), result.end());
|
||||
// we remove all links to origin features and origins, they belong to a CS too and can't be
|
||||
// moved
|
||||
result.erase(std::remove_if(result.begin(),
|
||||
result.end(),
|
||||
[](App::DocumentObject* obj) -> bool {
|
||||
return (obj->isDerivedFrom(App::OriginFeature::getClassTypeId())
|
||||
|| obj->isDerivedFrom(App::Origin::getClassTypeId()));
|
||||
}),
|
||||
result.end());
|
||||
|
||||
vec.insert(vec.end(), result.begin(), result.end());
|
||||
|
||||
//post process the vector
|
||||
// post process the vector
|
||||
std::sort(vec.begin(), vec.end());
|
||||
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
|
||||
}
|
||||
|
||||
void GeoFeatureGroupExtension::getCSInList(const DocumentObject* obj,
|
||||
std::vector< DocumentObject* >& vec) {
|
||||
std::vector<DocumentObject*>& vec)
|
||||
{
|
||||
|
||||
if(!obj)
|
||||
if (!obj) {
|
||||
return;
|
||||
|
||||
//search the inlist for objects that have non-expression links to us
|
||||
for(App::DocumentObject* parent : obj->getInList()) {
|
||||
|
||||
//not interested in other groups (and here we mean all groups, normal ones and geofeaturegroup)
|
||||
if(parent->hasExtension(App::GroupExtension::getExtensionClassTypeId()))
|
||||
continue;
|
||||
|
||||
//check if the link is real Local scope one or if it is a expression one (could also be both, so it is not
|
||||
//enough to check the expressions)
|
||||
auto res = getScopedObjectsFromLinks(parent, LinkScope::Local);
|
||||
if(std::find(res.begin(), res.end(), obj) != res.end())
|
||||
vec.push_back(parent);
|
||||
}
|
||||
|
||||
//clear all duplicates
|
||||
// search the inlist for objects that have non-expression links to us
|
||||
for (App::DocumentObject* parent : obj->getInList()) {
|
||||
|
||||
// not interested in other groups (and here we mean all groups, normal ones and
|
||||
// geofeaturegroup)
|
||||
if (parent->hasExtension(App::GroupExtension::getExtensionClassTypeId())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if the link is real Local scope one or if it is a expression one (could also be
|
||||
// both, so it is not enough to check the expressions)
|
||||
auto res = getScopedObjectsFromLinks(parent, LinkScope::Local);
|
||||
if (std::find(res.begin(), res.end(), obj) != res.end()) {
|
||||
vec.push_back(parent);
|
||||
}
|
||||
}
|
||||
|
||||
// clear all duplicates
|
||||
std::sort(vec.begin(), vec.end());
|
||||
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
|
||||
}
|
||||
|
||||
std::vector< DocumentObject* > GeoFeatureGroupExtension::getCSRelevantLinks(const DocumentObject* obj) {
|
||||
std::vector<DocumentObject*> GeoFeatureGroupExtension::getCSRelevantLinks(const DocumentObject* obj)
|
||||
{
|
||||
|
||||
if(!obj)
|
||||
if (!obj) {
|
||||
return {};
|
||||
}
|
||||
|
||||
//get all out links
|
||||
// get all out links
|
||||
std::vector<DocumentObject*> vec;
|
||||
|
||||
recursiveCSRelevantLinks(obj, vec);
|
||||
|
||||
//post process the list after we added many things
|
||||
// post process the list after we added many things
|
||||
std::sort(vec.begin(), vec.end());
|
||||
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
|
||||
vec.erase(std::remove(vec.begin(), vec.end(), obj), vec.end());
|
||||
@@ -333,53 +373,63 @@ std::vector< DocumentObject* > GeoFeatureGroupExtension::getCSRelevantLinks(cons
|
||||
}
|
||||
|
||||
void GeoFeatureGroupExtension::recursiveCSRelevantLinks(const DocumentObject* obj,
|
||||
std::vector< DocumentObject* >& vec) {
|
||||
std::vector<DocumentObject*>& vec)
|
||||
{
|
||||
|
||||
if(!obj)
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector< DocumentObject* > links;
|
||||
std::vector<DocumentObject*> links;
|
||||
getCSOutList(obj, links);
|
||||
getCSInList(obj, links);
|
||||
|
||||
//go on traversing the graph in all directions!
|
||||
for(auto o : links) {
|
||||
if(!o || o == obj || std::find(vec.begin(), vec.end(), o) != vec.end())
|
||||
// go on traversing the graph in all directions!
|
||||
for (auto o : links) {
|
||||
if (!o || o == obj || std::find(vec.begin(), vec.end(), o) != vec.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
vec.push_back(o);
|
||||
recursiveCSRelevantLinks(o, vec);
|
||||
}
|
||||
}
|
||||
|
||||
bool GeoFeatureGroupExtension::extensionGetSubObject(DocumentObject *&ret, const char *subname,
|
||||
PyObject **pyObj, Base::Matrix4D *mat, bool transform, int depth) const
|
||||
bool GeoFeatureGroupExtension::extensionGetSubObject(DocumentObject*& ret,
|
||||
const char* subname,
|
||||
PyObject** pyObj,
|
||||
Base::Matrix4D* mat,
|
||||
bool transform,
|
||||
int depth) const
|
||||
{
|
||||
ret = nullptr;
|
||||
const char *dot;
|
||||
if(!subname || *subname==0) {
|
||||
const char* dot;
|
||||
if (!subname || *subname == 0) {
|
||||
auto obj = dynamic_cast<const DocumentObject*>(getExtendedContainer());
|
||||
ret = const_cast<DocumentObject*>(obj);
|
||||
if(mat && transform)
|
||||
if (mat && transform) {
|
||||
*mat *= const_cast<GeoFeatureGroupExtension*>(this)->placement().getValue().toMatrix();
|
||||
}else if((dot=strchr(subname,'.'))) {
|
||||
if(subname[0]!='$')
|
||||
ret = Group.findUsingMap(std::string(subname,dot));
|
||||
else{
|
||||
std::string name = std::string(subname+1,dot);
|
||||
for(auto child : Group.getValues()) {
|
||||
if(name == child->Label.getStrValue()){
|
||||
}
|
||||
}
|
||||
else if ((dot = strchr(subname, '.'))) {
|
||||
if (subname[0] != '$') {
|
||||
ret = Group.findUsingMap(std::string(subname, dot));
|
||||
}
|
||||
else {
|
||||
std::string name = std::string(subname + 1, dot);
|
||||
for (auto child : Group.getValues()) {
|
||||
if (name == child->Label.getStrValue()) {
|
||||
ret = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ret) {
|
||||
if(dot) ++dot;
|
||||
if(dot && *dot
|
||||
&& !ret->hasExtension(App::LinkBaseExtension::getExtensionClassTypeId())
|
||||
&& !ret->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId()))
|
||||
{
|
||||
if (ret) {
|
||||
if (dot) {
|
||||
++dot;
|
||||
}
|
||||
if (dot && *dot && !ret->hasExtension(App::LinkBaseExtension::getExtensionClassTypeId())
|
||||
&& !ret->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId())) {
|
||||
// Consider this
|
||||
// Body
|
||||
// | -- Pad
|
||||
@@ -391,33 +441,37 @@ bool GeoFeatureGroupExtension::extensionGetSubObject(DocumentObject *&ret, const
|
||||
// getSubObject(Pad,"Sketch.") as this will transform Sketch
|
||||
// using Pad's placement.
|
||||
//
|
||||
const char *next = strchr(dot,'.');
|
||||
if(next) {
|
||||
App::DocumentObject *nret=nullptr;
|
||||
extensionGetSubObject(nret,dot,pyObj,mat,transform,depth+1);
|
||||
if(nret) {
|
||||
const char* next = strchr(dot, '.');
|
||||
if (next) {
|
||||
App::DocumentObject* nret = nullptr;
|
||||
extensionGetSubObject(nret, dot, pyObj, mat, transform, depth + 1);
|
||||
if (nret) {
|
||||
ret = nret;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(mat && transform)
|
||||
*mat *= const_cast<GeoFeatureGroupExtension*>(this)->placement().getValue().toMatrix();
|
||||
ret = ret->getSubObject(dot?dot:"",pyObj,mat,true,depth+1);
|
||||
if (mat && transform) {
|
||||
*mat *=
|
||||
const_cast<GeoFeatureGroupExtension*>(this)->placement().getValue().toMatrix();
|
||||
}
|
||||
ret = ret->getSubObject(dot ? dot : "", pyObj, mat, true, depth + 1);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GeoFeatureGroupExtension::areLinksValid(const DocumentObject* obj) {
|
||||
bool GeoFeatureGroupExtension::areLinksValid(const DocumentObject* obj)
|
||||
{
|
||||
|
||||
if(!obj)
|
||||
if (!obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<App::Property*> list;
|
||||
obj->getPropertyList(list);
|
||||
for(App::Property* prop : list) {
|
||||
if(!isLinkValid(prop)) {
|
||||
for (App::Property* prop : list) {
|
||||
if (!isLinkValid(prop)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -425,65 +479,79 @@ bool GeoFeatureGroupExtension::areLinksValid(const DocumentObject* obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GeoFeatureGroupExtension::isLinkValid(App::Property* prop) {
|
||||
bool GeoFeatureGroupExtension::isLinkValid(App::Property* prop)
|
||||
{
|
||||
|
||||
if(!prop)
|
||||
if (!prop) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//get the object that holds the property
|
||||
if(!prop->getContainer()->isDerivedFrom(App::DocumentObject::getClassTypeId()))
|
||||
return true; //this link comes not from a document object, scopes are meaningless
|
||||
// get the object that holds the property
|
||||
if (!prop->getContainer()->isDerivedFrom(App::DocumentObject::getClassTypeId())) {
|
||||
return true; // this link comes not from a document object, scopes are meaningless
|
||||
}
|
||||
auto obj = static_cast<App::DocumentObject*>(prop->getContainer());
|
||||
|
||||
//no cross CS link for local links.
|
||||
// no cross CS link for local links.
|
||||
auto result = getScopedObjectsFromLink(prop, LinkScope::Local);
|
||||
auto group = getGroupOfObject(obj);
|
||||
for(auto link : result) {
|
||||
if(getGroupOfObject(link) != group)
|
||||
for (auto link : result) {
|
||||
if (getGroupOfObject(link) != group) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//for links with scope SubGroup we need to check if all features are part of subgroups
|
||||
if(obj->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId())) {
|
||||
// for links with scope SubGroup we need to check if all features are part of subgroups
|
||||
if (obj->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId())) {
|
||||
result = getScopedObjectsFromLink(prop, LinkScope::Child);
|
||||
auto groupExt = obj->getExtensionByType<App::GeoFeatureGroupExtension>();
|
||||
for(auto link : result) {
|
||||
if(!groupExt->hasObject(link, true))
|
||||
for (auto link : result) {
|
||||
if (!groupExt->hasObject(link, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GeoFeatureGroupExtension::getInvalidLinkObjects(const DocumentObject* obj, std::vector< DocumentObject* >& vec) {
|
||||
void GeoFeatureGroupExtension::getInvalidLinkObjects(const DocumentObject* obj,
|
||||
std::vector<DocumentObject*>& vec)
|
||||
{
|
||||
|
||||
if(!obj)
|
||||
if (!obj) {
|
||||
return;
|
||||
|
||||
//no cross CS link for local links.
|
||||
auto result = getScopedObjectsFromLinks(obj, LinkScope::Local);
|
||||
auto group = obj->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId()) ? obj : getGroupOfObject(obj);
|
||||
for(auto link : result) {
|
||||
if(getGroupOfObject(link) != group)
|
||||
vec.push_back(link);
|
||||
}
|
||||
|
||||
//for links with scope SubGroup we need to check if all features are part of subgroups
|
||||
if(group) {
|
||||
// no cross CS link for local links.
|
||||
auto result = getScopedObjectsFromLinks(obj, LinkScope::Local);
|
||||
auto group = obj->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId())
|
||||
? obj
|
||||
: getGroupOfObject(obj);
|
||||
for (auto link : result) {
|
||||
if (getGroupOfObject(link) != group) {
|
||||
vec.push_back(link);
|
||||
}
|
||||
}
|
||||
|
||||
// for links with scope SubGroup we need to check if all features are part of subgroups
|
||||
if (group) {
|
||||
result = getScopedObjectsFromLinks(obj, LinkScope::Child);
|
||||
auto groupExt = group->getExtensionByType<App::GeoFeatureGroupExtension>();
|
||||
for(auto link : result) {
|
||||
if(!groupExt->hasObject(link, true))
|
||||
for (auto link : result) {
|
||||
if (!groupExt->hasObject(link, true)) {
|
||||
vec.push_back(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GeoFeatureGroupExtension::extensionGetSubObjects(std::vector<std::string> &ret, int) const {
|
||||
for(auto obj : Group.getValues()) {
|
||||
if(obj && obj->isAttachedToDocument() && !obj->testStatus(ObjectStatus::GeoExcluded))
|
||||
ret.push_back(std::string(obj->getNameInDocument())+'.');
|
||||
bool GeoFeatureGroupExtension::extensionGetSubObjects(std::vector<std::string>& ret, int) const
|
||||
{
|
||||
for (auto obj : Group.getValues()) {
|
||||
if (obj && obj->isAttachedToDocument() && !obj->testStatus(ObjectStatus::GeoExcluded)) {
|
||||
ret.push_back(std::string(obj->getNameInDocument()) + '.');
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -491,9 +559,11 @@ bool GeoFeatureGroupExtension::extensionGetSubObjects(std::vector<std::string> &
|
||||
|
||||
// Python feature ---------------------------------------------------------
|
||||
|
||||
namespace App {
|
||||
EXTENSION_PROPERTY_SOURCE_TEMPLATE(App::GeoFeatureGroupExtensionPython, App::GeoFeatureGroupExtension)
|
||||
namespace App
|
||||
{
|
||||
EXTENSION_PROPERTY_SOURCE_TEMPLATE(App::GeoFeatureGroupExtensionPython,
|
||||
App::GeoFeatureGroupExtension)
|
||||
|
||||
// explicit template instantiation
|
||||
template class AppExport ExtensionPythonT<GroupExtensionPythonT<GeoFeatureGroupExtension>>;
|
||||
}
|
||||
} // namespace App
|
||||
|
||||
@@ -35,21 +35,23 @@ namespace App
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The base class for placeable group of DocumentObjects. It represents a local coordnate system
|
||||
* @brief The base class for placeable group of DocumentObjects. It represents a local coordnate
|
||||
* system
|
||||
*
|
||||
* This class is the FreeCAD way of representing local coordinate systems. It groups its children beneath
|
||||
* it and transforms them all with the GeoFeatureGroup placement. A few important properties:
|
||||
* - Every child that belongs to the CS must be in the Group property. Even if a sketch is part of a pad,
|
||||
* it must be in the Group property of the same GeoFeatureGroup as pad. This also holds for normal
|
||||
* GroupExtensions. They can be added to a GeoFeatureGroup, but all objects that the group holds must
|
||||
* also be added to the GeoFeatureGroup
|
||||
* This class is the FreeCAD way of representing local coordinate systems. It groups its children
|
||||
* beneath it and transforms them all with the GeoFeatureGroup placement. A few important
|
||||
* properties:
|
||||
* - Every child that belongs to the CS must be in the Group property. Even if a sketch is part of a
|
||||
* pad, it must be in the Group property of the same GeoFeatureGroup as pad. This also holds for
|
||||
* normal GroupExtensions. They can be added to a GeoFeatureGroup, but all objects that the group
|
||||
* holds must also be added to the GeoFeatureGroup
|
||||
* - Objects can be only in a single GeoFeatureGroup. It is not allowed to have a document object in
|
||||
* multiple GeoFeatureGroups
|
||||
* - PropertyLinks between different GeoFeatureGroups are forbidden. There are special link properties
|
||||
* that allow such cross-CS links.
|
||||
* - PropertyLinks between different GeoFeatureGroups are forbidden. There are special link
|
||||
* properties that allow such cross-CS links.
|
||||
* - Expressions can cross GeoFeatureGroup borders
|
||||
*/
|
||||
class AppExport GeoFeatureGroupExtension : public App::GroupExtension
|
||||
class AppExport GeoFeatureGroupExtension: public App::GroupExtension
|
||||
{
|
||||
using inherited = App::GroupExtension;
|
||||
EXTENSION_PROPERTY_HEADER_WITH_OVERRIDE(App::GeoFeatureGroupExtension);
|
||||
@@ -65,7 +67,7 @@ public:
|
||||
* features.
|
||||
* @param transform (input).
|
||||
*/
|
||||
virtual void transformPlacement(const Base::Placement &transform);
|
||||
virtual void transformPlacement(const Base::Placement& transform);
|
||||
|
||||
/// Constructor
|
||||
GeoFeatureGroupExtension();
|
||||
@@ -84,65 +86,77 @@ public:
|
||||
* @brief Calculates the global placement of this group
|
||||
*
|
||||
* The returned placement describes the transformation from the global reference coordinate
|
||||
* system to the local coordinate system of this geo feature group. If this group has a no parent
|
||||
* GeoFeatureGroup the returned placement is the one of this group. For multiple stacked
|
||||
* system to the local coordinate system of this geo feature group. If this group has a no
|
||||
* parent GeoFeatureGroup the returned placement is the one of this group. For multiple stacked
|
||||
* GeoFeatureGroups the returned Placement is the combination of all parent placements including
|
||||
* the one of this group.
|
||||
* @return Base::Placement The transformation from global reference system to the groups local system
|
||||
* @return Base::Placement The transformation from global reference system to the groups local
|
||||
* system
|
||||
*/
|
||||
Base::Placement globalGroupPlacement();
|
||||
|
||||
/// Returns true if the given DocumentObject is DocumentObjectGroup but not GeoFeatureGroup
|
||||
static bool isNonGeoGroup(const DocumentObject* obj) {
|
||||
return obj->hasExtension(GroupExtension::getExtensionClassTypeId()) &&
|
||||
!obj->hasExtension(GeoFeatureGroupExtension::getExtensionClassTypeId());
|
||||
static bool isNonGeoGroup(const DocumentObject* obj)
|
||||
{
|
||||
return obj->hasExtension(GroupExtension::getExtensionClassTypeId())
|
||||
&& !obj->hasExtension(GeoFeatureGroupExtension::getExtensionClassTypeId());
|
||||
}
|
||||
|
||||
bool extensionGetSubObject(DocumentObject *&ret, const char *subname, PyObject **pyObj,
|
||||
Base::Matrix4D *mat, bool transform, int depth) const override;
|
||||
bool extensionGetSubObject(DocumentObject*& ret,
|
||||
const char* subname,
|
||||
PyObject** pyObj,
|
||||
Base::Matrix4D* mat,
|
||||
bool transform,
|
||||
int depth) const override;
|
||||
|
||||
bool extensionGetSubObjects(std::vector<std::string> &ret, int reason) const override;
|
||||
bool extensionGetSubObjects(std::vector<std::string>& ret, int reason) const override;
|
||||
|
||||
std::vector< DocumentObject* > addObjects(std::vector< DocumentObject* > obj) override;
|
||||
std::vector< DocumentObject* > removeObjects(std::vector< DocumentObject* > obj) override;
|
||||
std::vector<DocumentObject*> addObjects(std::vector<DocumentObject*> obj) override;
|
||||
std::vector<DocumentObject*> removeObjects(std::vector<DocumentObject*> obj) override;
|
||||
|
||||
/// Collects all links that are relevant for the coordinate system, meaning all recursive links to
|
||||
/// obj and from obj excluding expressions and stopping the recursion at other geofeaturegroups.
|
||||
/// The result is the combination of CSOutList and CSInList.
|
||||
/// Collects all links that are relevant for the coordinate system, meaning all recursive links
|
||||
/// to obj and from obj excluding expressions and stopping the recursion at other
|
||||
/// geofeaturegroups. The result is the combination of CSOutList and CSInList.
|
||||
static std::vector<App::DocumentObject*> getCSRelevantLinks(const App::DocumentObject* obj);
|
||||
/// Checks if the links of the given object comply with all GeoFeatureGroup requirements, that means
|
||||
/// if normal links are only within the parent GeoFeatureGroup.
|
||||
/// Checks if the links of the given object comply with all GeoFeatureGroup requirements, that
|
||||
/// means if normal links are only within the parent GeoFeatureGroup.
|
||||
static bool areLinksValid(const App::DocumentObject* obj);
|
||||
/// Checks if the given link complies with all GeoFeatureGroup requirements, that means
|
||||
/// if normal links are only within the parent GeoFeatureGroup.
|
||||
static bool isLinkValid(App::Property* link);
|
||||
//Returns all objects that are wrongly linked from this object, meaning which are out of scope of the
|
||||
//links of obj
|
||||
static void getInvalidLinkObjects(const App::DocumentObject* obj, std::vector<App::DocumentObject*>& vec);
|
||||
// Returns all objects that are wrongly linked from this object, meaning which are out of scope
|
||||
// of the links of obj
|
||||
static void getInvalidLinkObjects(const App::DocumentObject* obj,
|
||||
std::vector<App::DocumentObject*>& vec);
|
||||
|
||||
private:
|
||||
Base::Placement recursiveGroupPlacement(GeoFeatureGroupExtension* group, std::unordered_set<GeoFeatureGroupExtension*>& history);
|
||||
static std::vector<App::DocumentObject*> getScopedObjectsFromLinks(const App::DocumentObject*, LinkScope scope = LinkScope::Local);
|
||||
static std::vector<App::DocumentObject*> getScopedObjectsFromLink(App::Property*, LinkScope scope = LinkScope::Local);
|
||||
Base::Placement recursiveGroupPlacement(GeoFeatureGroupExtension* group,
|
||||
std::unordered_set<GeoFeatureGroupExtension*>& history);
|
||||
static std::vector<App::DocumentObject*>
|
||||
getScopedObjectsFromLinks(const App::DocumentObject*, LinkScope scope = LinkScope::Local);
|
||||
static std::vector<App::DocumentObject*>
|
||||
getScopedObjectsFromLink(App::Property*, LinkScope scope = LinkScope::Local);
|
||||
|
||||
/// Collects GeoFeatureGroup relevant objects that are linked from the given one. That means all linked objects
|
||||
/// except GeoFeatureGroups. Expressions links are ignored. Only local scope links are considered. There is no
|
||||
/// recursion. An exception is thrown when there are dependency loops.
|
||||
static void getCSOutList(const App::DocumentObject* obj, std::vector<App::DocumentObject*>& vec);
|
||||
/// Collects GeoFeatureGroup relevant objects that are linked from the given one. That means all
|
||||
/// linked objects except GeoFeatureGroups. Expressions links are ignored. Only local scope
|
||||
/// links are considered. There is no recursion. An exception is thrown when there are
|
||||
/// dependency loops.
|
||||
static void getCSOutList(const App::DocumentObject* obj,
|
||||
std::vector<App::DocumentObject*>& vec);
|
||||
/// Collects GeoFeatureGroup relevant objects that link to the given one. That means all objects
|
||||
/// except GeoFeatureGroups. Expression links are ignored. Only local scope links are relevant, and
|
||||
/// there is no recursion. An exception is thrown when there are dependency loops.
|
||||
/// except GeoFeatureGroups. Expression links are ignored. Only local scope links are relevant,
|
||||
/// and there is no recursion. An exception is thrown when there are dependency loops.
|
||||
static void getCSInList(const App::DocumentObject* obj, std::vector<App::DocumentObject*>& vec);
|
||||
|
||||
static void recursiveCSRelevantLinks(const App::DocumentObject* obj,
|
||||
std::vector<App::DocumentObject*>& vec);
|
||||
|
||||
};
|
||||
|
||||
using GeoFeatureGroupExtensionPython = ExtensionPythonT<GroupExtensionPythonT<GeoFeatureGroupExtension>>;
|
||||
using GeoFeatureGroupExtensionPython =
|
||||
ExtensionPythonT<GroupExtensionPythonT<GeoFeatureGroupExtension>>;
|
||||
|
||||
|
||||
} //namespace App
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // APP_GeoFeatureGroup_H
|
||||
#endif // APP_GeoFeatureGroup_H
|
||||
|
||||
@@ -36,7 +36,7 @@ std::string GeoFeatureGroupExtensionPy::representation() const
|
||||
return {"<GeoFeatureGroup object>"};
|
||||
}
|
||||
|
||||
PyObject *GeoFeatureGroupExtensionPy::getCustomAttributes(const char* /*attr*/) const
|
||||
PyObject* GeoFeatureGroupExtensionPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
@@ -45,5 +45,3 @@ int GeoFeatureGroupExtensionPy::setCustomAttributes(const char* /*attr*/, PyObje
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -37,16 +37,18 @@ std::string GeoFeaturePy::representation() const
|
||||
return {"<GeoFeature object>"};
|
||||
}
|
||||
|
||||
PyObject* GeoFeaturePy::getPaths(PyObject * /*args*/)
|
||||
PyObject* GeoFeaturePy::getPaths(PyObject* /*args*/)
|
||||
{
|
||||
PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PyObject* GeoFeaturePy::getGlobalPlacement(PyObject * args) {
|
||||
PyObject* GeoFeaturePy::getGlobalPlacement(PyObject* args)
|
||||
{
|
||||
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
Base::Placement p = static_cast<GeoFeature*>(getDocumentObjectPtr())->globalPlacement();
|
||||
@@ -57,7 +59,8 @@ PyObject* GeoFeaturePy::getGlobalPlacement(PyObject * args) {
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* GeoFeaturePy::getGlobalPlacementOf(PyObject * args) {
|
||||
PyObject* GeoFeaturePy::getGlobalPlacementOf(PyObject* args)
|
||||
{
|
||||
|
||||
PyObject* pyTargetObj {nullptr};
|
||||
PyObject* pyRootObj {nullptr};
|
||||
@@ -78,10 +81,11 @@ PyObject* GeoFeaturePy::getGlobalPlacementOf(PyObject * args) {
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* GeoFeaturePy::getPropertyNameOfGeometry(PyObject * args)
|
||||
PyObject* GeoFeaturePy::getPropertyNameOfGeometry(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GeoFeature* object = this->getGeoFeaturePtr();
|
||||
const PropertyComplexGeoData* prop = object->getPropertyOfGeometry();
|
||||
@@ -92,10 +96,11 @@ PyObject* GeoFeaturePy::getPropertyNameOfGeometry(PyObject * args)
|
||||
return Py::new_reference_to(Py::None());
|
||||
}
|
||||
|
||||
PyObject* GeoFeaturePy::getPropertyOfGeometry(PyObject * args)
|
||||
PyObject* GeoFeaturePy::getPropertyOfGeometry(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GeoFeature* object = this->getGeoFeaturePtr();
|
||||
const PropertyComplexGeoData* prop = object->getPropertyOfGeometry();
|
||||
@@ -105,7 +110,7 @@ PyObject* GeoFeaturePy::getPropertyOfGeometry(PyObject * args)
|
||||
return Py::new_reference_to(Py::None());
|
||||
}
|
||||
|
||||
PyObject *GeoFeaturePy::getCustomAttributes(const char* /*attr*/) const
|
||||
PyObject* GeoFeaturePy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
@@ -115,7 +120,8 @@ int GeoFeaturePy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
return 0;
|
||||
}
|
||||
|
||||
Py::String GeoFeaturePy::getElementMapVersion() const {
|
||||
return Py::String(getGeoFeaturePtr()->getElementMapVersion(
|
||||
getGeoFeaturePtr()->getPropertyOfGeometry()));
|
||||
Py::String GeoFeaturePy::getElementMapVersion() const
|
||||
{
|
||||
return Py::String(
|
||||
getGeoFeaturePtr()->getElementMapVersion(getGeoFeaturePtr()->getPropertyOfGeometry()));
|
||||
}
|
||||
|
||||
@@ -38,21 +38,22 @@
|
||||
using namespace App;
|
||||
using namespace boost;
|
||||
|
||||
void Document::writeDependencyGraphViz(std::ostream &out)
|
||||
void Document::writeDependencyGraphViz(std::ostream& out)
|
||||
{
|
||||
// // caching vertex to DocObject
|
||||
//std::map<Vertex,DocumentObject*> VertexMap;
|
||||
//for(std::map<DocumentObject*,Vertex>::const_iterator It1= _DepConMap.begin();It1 != _DepConMap.end(); ++It1)
|
||||
// std::map<Vertex,DocumentObject*> VertexMap;
|
||||
// for(std::map<DocumentObject*,Vertex>::const_iterator It1= _DepConMap.begin();It1 !=
|
||||
// _DepConMap.end(); ++It1)
|
||||
// VertexMap[It1->second] = It1->first;
|
||||
|
||||
out << "digraph G {" << std::endl;
|
||||
out << "\tordering=out;" << std::endl;
|
||||
out << "\tnode [shape = box];" << std::endl;
|
||||
|
||||
for (const auto &It : d->objectMap) {
|
||||
for (const auto& It : d->objectMap) {
|
||||
out << "\t" << It.first << ";" << std::endl;
|
||||
std::vector<DocumentObject*> OutList = It.second->getOutList();
|
||||
for (const auto &It2 : OutList) {
|
||||
for (const auto& It2 : OutList) {
|
||||
if (It2) {
|
||||
out << "\t" << It.first << "->" << It2->getNameInDocument() << ";" << std::endl;
|
||||
}
|
||||
@@ -75,14 +76,19 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
{
|
||||
/* Type defs for a graph with graphviz attributes */
|
||||
using GraphvizAttributes = std::map<std::string, std::string>;
|
||||
using Graph = boost::subgraph< adjacency_list<vecS, vecS, directedS,
|
||||
property<vertex_attribute_t, GraphvizAttributes>,
|
||||
property<edge_index_t, int, property<edge_attribute_t, GraphvizAttributes> >,
|
||||
property<graph_name_t, std::string,
|
||||
property<graph_graph_attribute_t, GraphvizAttributes,
|
||||
property<graph_vertex_attribute_t, GraphvizAttributes,
|
||||
property<graph_edge_attribute_t, GraphvizAttributes>
|
||||
> > > > >;
|
||||
using Graph = boost::subgraph<adjacency_list<
|
||||
vecS,
|
||||
vecS,
|
||||
directedS,
|
||||
property<vertex_attribute_t, GraphvizAttributes>,
|
||||
property<edge_index_t, int, property<edge_attribute_t, GraphvizAttributes>>,
|
||||
property<graph_name_t,
|
||||
std::string,
|
||||
property<graph_graph_attribute_t,
|
||||
GraphvizAttributes,
|
||||
property<graph_vertex_attribute_t,
|
||||
GraphvizAttributes,
|
||||
property<graph_edge_attribute_t, GraphvizAttributes>>>>>>;
|
||||
|
||||
/**
|
||||
* @brief The GraphCreator class
|
||||
@@ -91,18 +97,25 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
*
|
||||
*/
|
||||
|
||||
class GraphCreator {
|
||||
class GraphCreator
|
||||
{
|
||||
public:
|
||||
|
||||
explicit GraphCreator(struct DocumentP* _d) : d(_d), seed(std::random_device()()), distribution(0,255) {
|
||||
explicit GraphCreator(struct DocumentP* _d)
|
||||
: d(_d)
|
||||
, seed(std::random_device()())
|
||||
, distribution(0, 255)
|
||||
{
|
||||
build();
|
||||
}
|
||||
|
||||
const Graph & getGraph() const { return DepList; }
|
||||
const Graph& getGraph() const
|
||||
{
|
||||
return DepList;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void build() {
|
||||
void build()
|
||||
{
|
||||
// Set attribute(s) for main graph
|
||||
get_property(DepList, graph_graph_attribute)["compound"] = "true";
|
||||
|
||||
@@ -119,7 +132,8 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
* @return A string
|
||||
*/
|
||||
|
||||
std::string getId(const DocumentObject * docObj) {
|
||||
std::string getId(const DocumentObject* docObj)
|
||||
{
|
||||
std::string id;
|
||||
if (docObj->isAttachedToDocument()) {
|
||||
auto doc = docObj->getDocument();
|
||||
@@ -136,25 +150,32 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
* @return A string
|
||||
*/
|
||||
|
||||
std::string getId(const ObjectIdentifier & path) {
|
||||
DocumentObject * docObj = path.getDocumentObject();
|
||||
if (!docObj)
|
||||
std::string getId(const ObjectIdentifier& path)
|
||||
{
|
||||
DocumentObject* docObj = path.getDocumentObject();
|
||||
if (!docObj) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::string((docObj)->getDocument()->getName()) + "#" + docObj->getNameInDocument() + "." + path.getPropertyName() + path.getSubPathStr();
|
||||
return std::string((docObj)->getDocument()->getName()) + "#"
|
||||
+ docObj->getNameInDocument() + "." + path.getPropertyName() + path.getSubPathStr();
|
||||
}
|
||||
|
||||
std::string getClusterName(const DocumentObject * docObj) const {
|
||||
std::string getClusterName(const DocumentObject* docObj) const
|
||||
{
|
||||
return std::string("cluster") + docObj->getNameInDocument();
|
||||
}
|
||||
|
||||
void setGraphLabel(Graph& g, const DocumentObject* obj) const {
|
||||
void setGraphLabel(Graph& g, const DocumentObject* obj) const
|
||||
{
|
||||
std::string name(obj->getNameInDocument());
|
||||
std::string label(obj->Label.getValue());
|
||||
if (name == label)
|
||||
if (name == label) {
|
||||
get_property(g, graph_graph_attribute)["label"] = name;
|
||||
else
|
||||
}
|
||||
else {
|
||||
get_property(g, graph_graph_attribute)["label"] = name + "\n(" + label + ")";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,7 +183,8 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
* @param obj DocumentObject
|
||||
*/
|
||||
|
||||
void setGraphAttributes(const DocumentObject * obj) {
|
||||
void setGraphAttributes(const DocumentObject* obj)
|
||||
{
|
||||
assert(GraphList.find(obj) != GraphList.end());
|
||||
get_property(*GraphList[obj], graph_name) = getClusterName(obj);
|
||||
|
||||
@@ -179,7 +201,8 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
* @param name Name of node
|
||||
*/
|
||||
|
||||
void setPropertyVertexAttributes(Graph & g, Vertex vertex, const std::string & name) {
|
||||
void setPropertyVertexAttributes(Graph& g, Vertex vertex, const std::string& name)
|
||||
{
|
||||
get(vertex_attribute, g)[vertex]["label"] = name;
|
||||
get(vertex_attribute, g)[vertex]["shape"] = "box";
|
||||
get(vertex_attribute, g)[vertex]["style"] = "dashed";
|
||||
@@ -187,13 +210,15 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief addExpressionSubgraphIfNeeded Add a subgraph to the main graph if it is needed, i.e. there are defined at least one
|
||||
* expression in the document object, or other objects are referencing properties in it.
|
||||
* @brief addExpressionSubgraphIfNeeded Add a subgraph to the main graph if it is needed,
|
||||
* i.e. there are defined at least one expression in the document object, or other objects
|
||||
* are referencing properties in it.
|
||||
* @param obj DocumentObject to assess.
|
||||
* @param CSSubgraphs Boolean if the GeoFeatureGroups are created as subgraphs
|
||||
*/
|
||||
|
||||
void addExpressionSubgraphIfNeeded(DocumentObject * obj, bool CSsubgraphs) {
|
||||
void addExpressionSubgraphIfNeeded(DocumentObject* obj, bool CSsubgraphs)
|
||||
{
|
||||
|
||||
auto expressions = obj->ExpressionEngine.getExpressions();
|
||||
|
||||
@@ -205,8 +230,9 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
auto group = GeoFeatureGroupExtension::getGroupOfObject(obj);
|
||||
if (group) {
|
||||
auto it = GraphList.find(group);
|
||||
if (it != GraphList.end())
|
||||
if (it != GraphList.end()) {
|
||||
graph = it->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,16 +242,18 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
setGraphAttributes(obj);
|
||||
}
|
||||
|
||||
// Create subgraphs for all document objects that it depends on; it will depend on some property there
|
||||
for (const auto &expr : expressions) {
|
||||
// Create subgraphs for all document objects that it depends on; it will depend on
|
||||
// some property there
|
||||
for (const auto& expr : expressions) {
|
||||
std::map<ObjectIdentifier, bool> deps;
|
||||
|
||||
expr.second->getIdentifiers(deps);
|
||||
|
||||
for (const auto &dep : deps) {
|
||||
if (dep.second)
|
||||
for (const auto& dep : deps) {
|
||||
if (dep.second) {
|
||||
continue;
|
||||
DocumentObject * o = dep.first.getDocumentObject();
|
||||
}
|
||||
DocumentObject* o = dep.first.getDocumentObject();
|
||||
|
||||
// Doesn't exist already?
|
||||
if (o && !GraphList[o]) {
|
||||
@@ -249,38 +277,48 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief add Add @docObj to the graph, including all expressions (and dependencies) it includes.
|
||||
* @brief add Add @docObj to the graph, including all expressions (and dependencies) it
|
||||
* includes.
|
||||
* @param docObj The document object to add.
|
||||
* @param name Name of node.
|
||||
*/
|
||||
|
||||
void add(DocumentObject *docObj, const std::string &name, const std::string &label, bool CSSubgraphs)
|
||||
void add(DocumentObject* docObj,
|
||||
const std::string& name,
|
||||
const std::string& label,
|
||||
bool CSSubgraphs)
|
||||
{
|
||||
|
||||
//don't add objects twice
|
||||
if (std::find(objects.begin(), objects.end(), docObj) != objects.end())
|
||||
// don't add objects twice
|
||||
if (std::find(objects.begin(), objects.end(), docObj) != objects.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//find the correct graph to add the vertex to. Check first expression graphs, afterwards
|
||||
//the parent CS and origin graphs
|
||||
Graph *sgraph = GraphList[docObj];
|
||||
// find the correct graph to add the vertex to. Check first expression graphs,
|
||||
// afterwards the parent CS and origin graphs
|
||||
Graph* sgraph = GraphList[docObj];
|
||||
if (CSSubgraphs) {
|
||||
if (!sgraph) {
|
||||
auto group = GeoFeatureGroupExtension::getGroupOfObject(docObj);
|
||||
if (group) {
|
||||
if (docObj->isDerivedFrom(App::OriginFeature::getClassTypeId()))
|
||||
sgraph = GraphList[group->getExtensionByType<OriginGroupExtension>()->Origin.getValue()];
|
||||
else
|
||||
if (docObj->isDerivedFrom(App::OriginFeature::getClassTypeId())) {
|
||||
sgraph = GraphList[group->getExtensionByType<OriginGroupExtension>()
|
||||
->Origin.getValue()];
|
||||
}
|
||||
else {
|
||||
sgraph = GraphList[group];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!sgraph) {
|
||||
if (docObj->isDerivedFrom(OriginFeature::getClassTypeId()))
|
||||
sgraph = GraphList[static_cast<OriginFeature *>(docObj)->getOrigin()];
|
||||
if (docObj->isDerivedFrom(OriginFeature::getClassTypeId())) {
|
||||
sgraph = GraphList[static_cast<OriginFeature*>(docObj)->getOrigin()];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!sgraph)
|
||||
if (!sgraph) {
|
||||
sgraph = &DepList;
|
||||
}
|
||||
|
||||
// Keep a list of all added document objects.
|
||||
objects.insert(docObj);
|
||||
@@ -294,21 +332,25 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
get(vertex_attribute, *sgraph)[LocalVertexList[getId(docObj)]]["style"] = "filled";
|
||||
get(vertex_attribute, *sgraph)[LocalVertexList[getId(docObj)]]["shape"] = "Mrecord";
|
||||
// Set node label
|
||||
if (name == label)
|
||||
if (name == label) {
|
||||
get(vertex_attribute, *sgraph)[LocalVertexList[getId(docObj)]]["label"] = name;
|
||||
else
|
||||
get(vertex_attribute, *sgraph)[LocalVertexList[getId(docObj)]]["label"] = name + "\n(" + label + ")";
|
||||
}
|
||||
else {
|
||||
get(vertex_attribute, *sgraph)[LocalVertexList[getId(docObj)]]["label"] =
|
||||
name + "\n(" + label + ")";
|
||||
}
|
||||
}
|
||||
else {
|
||||
get(vertex_attribute, *sgraph)[LocalVertexList[getId(docObj)]]["style"] = "invis";
|
||||
get(vertex_attribute, *sgraph)[LocalVertexList[getId(docObj)]]["fixedsize"] = "true";
|
||||
get(vertex_attribute, *sgraph)[LocalVertexList[getId(docObj)]]["fixedsize"] =
|
||||
"true";
|
||||
get(vertex_attribute, *sgraph)[LocalVertexList[getId(docObj)]]["width"] = "0";
|
||||
get(vertex_attribute, *sgraph)[LocalVertexList[getId(docObj)]]["height"] = "0";
|
||||
}
|
||||
|
||||
// Add expressions and its dependencies
|
||||
auto expressions{docObj->ExpressionEngine.getExpressions()};
|
||||
for (const auto &expr : expressions) {
|
||||
auto expressions {docObj->ExpressionEngine.getExpressions()};
|
||||
for (const auto& expr : expressions) {
|
||||
auto found = std::as_const(GlobalVertexList).find(getId(expr.first));
|
||||
if (found == GlobalVertexList.end()) {
|
||||
int vid = LocalVertexList[getId(expr.first)] = add_vertex(*sgraph);
|
||||
@@ -318,63 +360,70 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
}
|
||||
|
||||
// Add all dependencies
|
||||
for (const auto &expression : expressions) {
|
||||
for (const auto& expression : expressions) {
|
||||
// Get dependencies
|
||||
std::map<ObjectIdentifier, bool> deps;
|
||||
expression.second->getIdentifiers(deps);
|
||||
|
||||
// Create subgraphs for all documentobjects that it depends on; it will depend on some property there
|
||||
for (const auto &dep : deps) {
|
||||
// Create subgraphs for all documentobjects that it depends on; it will depend on
|
||||
// some property there
|
||||
for (const auto& dep : deps) {
|
||||
if (dep.second) {
|
||||
continue;
|
||||
}
|
||||
DocumentObject *depObjDoc = dep.first.getDocumentObject();
|
||||
DocumentObject* depObjDoc = dep.first.getDocumentObject();
|
||||
auto found = GlobalVertexList.find(getId(dep.first));
|
||||
|
||||
if (found == GlobalVertexList.end()) {
|
||||
Graph *depSgraph = GraphList[depObjDoc] ? GraphList[depObjDoc] : &DepList;
|
||||
Graph* depSgraph = GraphList[depObjDoc] ? GraphList[depObjDoc] : &DepList;
|
||||
|
||||
LocalVertexList[getId(dep.first)] = add_vertex(*depSgraph);
|
||||
GlobalVertexList[getId(dep.first)] = vertex_no++;
|
||||
setPropertyVertexAttributes(*depSgraph, LocalVertexList[getId(dep.first)], dep.first.getPropertyName() + dep.first.getSubPathStr());
|
||||
setPropertyVertexAttributes(*depSgraph,
|
||||
LocalVertexList[getId(dep.first)],
|
||||
dep.first.getPropertyName()
|
||||
+ dep.first.getSubPathStr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void recursiveCSSubgraphs(DocumentObject* cs, DocumentObject* parent) {
|
||||
void recursiveCSSubgraphs(DocumentObject* cs, DocumentObject* parent)
|
||||
{
|
||||
|
||||
auto graph = parent ? GraphList[parent] : &DepList;
|
||||
// check if the value for the key 'parent' is null
|
||||
if (!graph)
|
||||
if (!graph) {
|
||||
return;
|
||||
}
|
||||
auto& sub = graph->create_subgraph();
|
||||
GraphList[cs] = ⊂
|
||||
get_property(sub, graph_name) = getClusterName(cs);
|
||||
|
||||
//build random color string
|
||||
// build random color string
|
||||
std::stringstream stream;
|
||||
stream << "#" << std::setfill('0') << std::setw(2)<< std::hex << distribution(seed)
|
||||
<< std::setfill('0') << std::setw(2)<< std::hex << distribution(seed)
|
||||
<< std::setfill('0') << std::setw(2)<< std::hex << distribution(seed) << 80;
|
||||
stream << "#" << std::setfill('0') << std::setw(2) << std::hex << distribution(seed)
|
||||
<< std::setfill('0') << std::setw(2) << std::hex << distribution(seed)
|
||||
<< std::setfill('0') << std::setw(2) << std::hex << distribution(seed) << 80;
|
||||
std::string result(stream.str());
|
||||
|
||||
get_property(sub, graph_graph_attribute)["bgcolor"] = result;
|
||||
get_property(sub, graph_graph_attribute)["style"] = "rounded,filled";
|
||||
setGraphLabel(sub, cs);
|
||||
|
||||
for(auto obj : cs->getOutList()) {
|
||||
for (auto obj : cs->getOutList()) {
|
||||
if (obj->hasExtension(GeoFeatureGroupExtension::getExtensionClassTypeId())) {
|
||||
// in case of dependencies loops check if obj is already part of the
|
||||
// map to avoid infinite recursions
|
||||
auto it = GraphList.find(obj);
|
||||
if (it == GraphList.end())
|
||||
if (it == GraphList.end()) {
|
||||
recursiveCSSubgraphs(obj, cs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//setup the origin if available
|
||||
if(cs->hasExtension(App::OriginGroupExtension::getExtensionClassTypeId())) {
|
||||
// setup the origin if available
|
||||
if (cs->hasExtension(App::OriginGroupExtension::getExtensionClassTypeId())) {
|
||||
auto origin = cs->getExtensionByType<OriginGroupExtension>()->Origin.getValue();
|
||||
if (!origin) {
|
||||
std::cerr << "Origin feature not found" << std::endl;
|
||||
@@ -388,67 +437,80 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
}
|
||||
}
|
||||
|
||||
void addSubgraphs() {
|
||||
void addSubgraphs()
|
||||
{
|
||||
|
||||
ParameterGrp::handle depGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/DependencyGraph");
|
||||
ParameterGrp::handle depGrp = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/DependencyGraph");
|
||||
bool CSSubgraphs = depGrp->GetBool("GeoFeatureSubgraphs", true);
|
||||
|
||||
if(CSSubgraphs) {
|
||||
//first build up the coordinate system subgraphs
|
||||
if (CSSubgraphs) {
|
||||
// first build up the coordinate system subgraphs
|
||||
for (auto objectIt : d->objectArray) {
|
||||
// ignore groups inside other groups, these will be processed in one of the next recursive calls.
|
||||
// App::Origin now has the GeoFeatureGroupExtension but it should not move its
|
||||
// group symbol outside its parent
|
||||
if (!objectIt->isDerivedFrom(Origin::getClassTypeId()) &&
|
||||
objectIt->hasExtension(GeoFeatureGroupExtension::getExtensionClassTypeId()) &&
|
||||
GeoFeatureGroupExtension::getGroupOfObject(objectIt) == nullptr)
|
||||
{
|
||||
// ignore groups inside other groups, these will be processed in one of the next
|
||||
// recursive calls. App::Origin now has the GeoFeatureGroupExtension but it
|
||||
// should not move its group symbol outside its parent
|
||||
if (!objectIt->isDerivedFrom(Origin::getClassTypeId())
|
||||
&& objectIt->hasExtension(
|
||||
GeoFeatureGroupExtension::getExtensionClassTypeId())
|
||||
&& GeoFeatureGroupExtension::getGroupOfObject(objectIt) == nullptr) {
|
||||
recursiveCSSubgraphs(objectIt, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Internal document objects
|
||||
for (const auto & It : d->objectMap)
|
||||
for (const auto& It : d->objectMap) {
|
||||
addExpressionSubgraphIfNeeded(It.second, CSSubgraphs);
|
||||
}
|
||||
|
||||
// Add external document objects
|
||||
for (const auto & it : d->objectMap) {
|
||||
for (const auto& it : d->objectMap) {
|
||||
std::vector<DocumentObject*> OutList = it.second->getOutList();
|
||||
for (auto obj : OutList) {
|
||||
if (obj) {
|
||||
std::map<std::string,Vertex>::const_iterator item = GlobalVertexList.find(getId(obj));
|
||||
std::map<std::string, Vertex>::const_iterator item =
|
||||
GlobalVertexList.find(getId(obj));
|
||||
|
||||
if (item == GlobalVertexList.end())
|
||||
if (item == GlobalVertexList.end()) {
|
||||
addExpressionSubgraphIfNeeded(obj, CSSubgraphs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Filling up the adjacency List
|
||||
void buildAdjacencyList() {
|
||||
void buildAdjacencyList()
|
||||
{
|
||||
|
||||
ParameterGrp::handle depGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/DependencyGraph");
|
||||
ParameterGrp::handle depGrp = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/DependencyGraph");
|
||||
bool CSSubgraphs = depGrp->GetBool("GeoFeatureSubgraphs", true);
|
||||
|
||||
// Add internal document objects
|
||||
for (const auto & It : d->objectMap)
|
||||
add(It.second, It.second->getNameInDocument(), It.second->Label.getValue(), CSSubgraphs);
|
||||
for (const auto& It : d->objectMap) {
|
||||
add(It.second,
|
||||
It.second->getNameInDocument(),
|
||||
It.second->Label.getValue(),
|
||||
CSSubgraphs);
|
||||
}
|
||||
|
||||
// Add external document objects
|
||||
for (const auto & It : d->objectMap) {
|
||||
for (const auto& It : d->objectMap) {
|
||||
std::vector<DocumentObject*> OutList = It.second->getOutList();
|
||||
for (auto obj : OutList) {
|
||||
if (obj) {
|
||||
std::map<std::string,Vertex>::const_iterator item = GlobalVertexList.find(getId(obj));
|
||||
std::map<std::string, Vertex>::const_iterator item =
|
||||
GlobalVertexList.find(getId(obj));
|
||||
|
||||
if (item == GlobalVertexList.end()) {
|
||||
if (obj->isAttachedToDocument()) {
|
||||
add(obj,
|
||||
std::string(obj->getDocument()->getName()) + "#" + obj->getNameInDocument(),
|
||||
std::string(obj->getDocument()->getName()) + "#" + obj->Label.getValue(),
|
||||
std::string(obj->getDocument()->getName()) + "#"
|
||||
+ obj->getNameInDocument(),
|
||||
std::string(obj->getDocument()->getName()) + "#"
|
||||
+ obj->Label.getValue(),
|
||||
CSSubgraphs);
|
||||
}
|
||||
}
|
||||
@@ -457,31 +519,37 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
}
|
||||
}
|
||||
|
||||
void addEdges() {
|
||||
void addEdges()
|
||||
{
|
||||
// Get edge properties for main graph
|
||||
const boost::property_map<Graph, boost::edge_attribute_t>::type& edgeAttrMap = boost::get(boost::edge_attribute, DepList);
|
||||
const boost::property_map<Graph, boost::edge_attribute_t>::type& edgeAttrMap =
|
||||
boost::get(boost::edge_attribute, DepList);
|
||||
|
||||
// Track edges between document objects connected by expression dependencies
|
||||
std::set<std::pair<const DocumentObject*, const DocumentObject*> > existingEdges;
|
||||
std::set<std::pair<const DocumentObject*, const DocumentObject*>> existingEdges;
|
||||
|
||||
// Add edges between properties
|
||||
for (const auto &docObj : objects) {
|
||||
for (const auto& docObj : objects) {
|
||||
|
||||
// Add expressions and its dependencies
|
||||
auto expressions = docObj->ExpressionEngine.getExpressions();
|
||||
for (const auto &expr : expressions) {
|
||||
for (const auto& expr : expressions) {
|
||||
std::map<ObjectIdentifier, bool> deps;
|
||||
expr.second->getIdentifiers(deps);
|
||||
|
||||
// Create subgraphs for all documentobjects that it depends on; it will depend on some property there
|
||||
for (const auto &dep : deps) {
|
||||
if (dep.second)
|
||||
// Create subgraphs for all documentobjects that it depends on; it will depend
|
||||
// on some property there
|
||||
for (const auto& dep : deps) {
|
||||
if (dep.second) {
|
||||
continue;
|
||||
DocumentObject * depObjDoc = dep.first.getDocumentObject();
|
||||
}
|
||||
DocumentObject* depObjDoc = dep.first.getDocumentObject();
|
||||
Edge edge;
|
||||
bool inserted;
|
||||
|
||||
tie(edge, inserted) = add_edge(GlobalVertexList[getId(expr.first)], GlobalVertexList[getId(dep.first)], DepList);
|
||||
tie(edge, inserted) = add_edge(GlobalVertexList[getId(expr.first)],
|
||||
GlobalVertexList[getId(dep.first)],
|
||||
DepList);
|
||||
|
||||
// Add this edge to the set of all expression generated edges
|
||||
existingEdges.insert(std::make_pair(docObj, depObjDoc));
|
||||
@@ -493,54 +561,69 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
}
|
||||
}
|
||||
|
||||
ParameterGrp::handle depGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/DependencyGraph");
|
||||
ParameterGrp::handle depGrp = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/DependencyGraph");
|
||||
bool omitGeoFeatureGroups = depGrp->GetBool("GeoFeatureSubgraphs", true);
|
||||
|
||||
// Add edges between document objects
|
||||
for (const auto & It : d->objectMap) {
|
||||
for (const auto& It : d->objectMap) {
|
||||
|
||||
if(omitGeoFeatureGroups && It.second->isDerivedFrom(Origin::getClassTypeId())) {
|
||||
if (omitGeoFeatureGroups && It.second->isDerivedFrom(Origin::getClassTypeId())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::map<DocumentObject*, int> dups;
|
||||
std::vector<DocumentObject*> OutList = It.second->getOutList();
|
||||
const DocumentObject * docObj = It.second;
|
||||
const bool docObj_is_group = docObj->hasExtension(GeoFeatureGroupExtension::getExtensionClassTypeId());
|
||||
const DocumentObject* docObj = It.second;
|
||||
const bool docObj_is_group =
|
||||
docObj->hasExtension(GeoFeatureGroupExtension::getExtensionClassTypeId());
|
||||
|
||||
for (auto obj : OutList) {
|
||||
if (obj) {
|
||||
if(omitGeoFeatureGroups && docObj_is_group && GeoFeatureGroupExtension::getGroupOfObject(obj) == docObj) {
|
||||
if (omitGeoFeatureGroups && docObj_is_group
|
||||
&& GeoFeatureGroupExtension::getGroupOfObject(obj) == docObj) {
|
||||
continue;
|
||||
}
|
||||
// Count duplicate edges
|
||||
bool inserted = edge(GlobalVertexList[getId(docObj)], GlobalVertexList[getId(obj)], DepList).second;
|
||||
bool inserted = edge(GlobalVertexList[getId(docObj)],
|
||||
GlobalVertexList[getId(obj)],
|
||||
DepList)
|
||||
.second;
|
||||
if (inserted) {
|
||||
dups[obj]++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip edge if an expression edge already exists
|
||||
if (existingEdges.find(std::make_pair(docObj, obj)) != existingEdges.end())
|
||||
if (existingEdges.find(std::make_pair(docObj, obj))
|
||||
!= existingEdges.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add edge
|
||||
|
||||
Edge edge;
|
||||
|
||||
tie(edge, inserted) = add_edge(GlobalVertexList[getId(docObj)], GlobalVertexList[getId(obj)], DepList);
|
||||
tie(edge, inserted) = add_edge(GlobalVertexList[getId(docObj)],
|
||||
GlobalVertexList[getId(obj)],
|
||||
DepList);
|
||||
|
||||
// Set properties to make arrows go between subgraphs if needed
|
||||
if (GraphList[docObj])
|
||||
if (GraphList[docObj]) {
|
||||
edgeAttrMap[edge]["ltail"] = getClusterName(docObj);
|
||||
if (GraphList[obj])
|
||||
}
|
||||
if (GraphList[obj]) {
|
||||
edgeAttrMap[edge]["lhead"] = getClusterName(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set labels for duplicate edges
|
||||
for (const auto & dup : dups) {
|
||||
Edge e(edge(GlobalVertexList[getId(It.second)], GlobalVertexList[getId(dup.first)], DepList).first);
|
||||
for (const auto& dup : dups) {
|
||||
Edge e(edge(GlobalVertexList[getId(It.second)],
|
||||
GlobalVertexList[getId(dup.first)],
|
||||
DepList)
|
||||
.first);
|
||||
std::stringstream s;
|
||||
s << " " << (dup.second + 1) << "x";
|
||||
edgeAttrMap[e]["label"] = s.str();
|
||||
@@ -550,10 +633,11 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
|
||||
using EdgeMap = std::unordered_multimap<Vertex, Edge>;
|
||||
|
||||
void removeEdges(EdgeMap & in_edges,
|
||||
EdgeMap & out_edges,
|
||||
std::pair<EdgeMap::iterator, EdgeMap::iterator > i_pair,
|
||||
std::function<Vertex (const Edge&)> select_vertex) {
|
||||
void removeEdges(EdgeMap& in_edges,
|
||||
EdgeMap& out_edges,
|
||||
std::pair<EdgeMap::iterator, EdgeMap::iterator> i_pair,
|
||||
std::function<Vertex(const Edge&)> select_vertex)
|
||||
{
|
||||
auto i = i_pair.first;
|
||||
|
||||
while (i != i_pair.second) {
|
||||
@@ -562,10 +646,12 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
auto in_i = in_i_pair.first;
|
||||
|
||||
while (in_i != in_i_pair.second) {
|
||||
if (in_i->second == i->second)
|
||||
if (in_i->second == i->second) {
|
||||
in_i = in_edges.erase(in_i);
|
||||
else
|
||||
}
|
||||
else {
|
||||
++in_i;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove node from out_edges
|
||||
@@ -574,12 +660,13 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#elif defined (__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#endif
|
||||
|
||||
void markCycles() {
|
||||
void markCycles()
|
||||
{
|
||||
bool changed = true;
|
||||
std::unordered_set<Vertex> in_use;
|
||||
EdgeMap in_edges;
|
||||
@@ -588,8 +675,9 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
// Add all vertices to the in_use set
|
||||
graph_traits<Graph>::vertex_iterator vi, vi_end;
|
||||
tie(vi, vi_end) = vertices(DepList);
|
||||
for (; vi != vi_end; ++vi)
|
||||
for (; vi != vi_end; ++vi) {
|
||||
in_use.insert(*vi);
|
||||
}
|
||||
|
||||
// Add all edges to the in_edges and out_edges multimaps
|
||||
graph_traits<Graph>::edge_iterator ei, ei_end;
|
||||
@@ -616,21 +704,26 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
auto i_in_deg_pair = in_edges.equal_range(*uvi);
|
||||
auto i_out_deg_pair = out_edges.equal_range(*uvi);
|
||||
|
||||
if (i_in_deg_pair.first == in_edges.end() && i_out_deg_pair.first == out_edges.end()) {
|
||||
if (i_in_deg_pair.first == in_edges.end()
|
||||
&& i_out_deg_pair.first == out_edges.end()) {
|
||||
uvi = in_use.erase(uvi);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove out edges of nodes that don't have a single edge in
|
||||
if (i_in_deg_pair.first == in_edges.end()) {
|
||||
removeEdges(in_edges, out_edges, i_out_deg_pair, [&](Edge e) { return target(e, DepList); });
|
||||
removeEdges(in_edges, out_edges, i_out_deg_pair, [&](Edge e) {
|
||||
return target(e, DepList);
|
||||
});
|
||||
changed = true;
|
||||
i_out_deg_pair = out_edges.equal_range(*uvi);
|
||||
}
|
||||
|
||||
// Remove in edges of nodes that don't have a single edge out
|
||||
if (i_out_deg_pair.first == out_edges.end()) {
|
||||
removeEdges(out_edges, in_edges, i_in_deg_pair, [&](Edge e) { return source(e, DepList); });
|
||||
removeEdges(out_edges, in_edges, i_in_deg_pair, [&](Edge e) {
|
||||
return source(e, DepList);
|
||||
});
|
||||
changed = true;
|
||||
}
|
||||
|
||||
@@ -639,41 +732,48 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
}
|
||||
|
||||
// Update colors in graph
|
||||
const boost::property_map<Graph, boost::edge_attribute_t>::type& edgeAttrMap = boost::get(boost::edge_attribute, DepList);
|
||||
for (auto ei : out_edges)
|
||||
const boost::property_map<Graph, boost::edge_attribute_t>::type& edgeAttrMap =
|
||||
boost::get(boost::edge_attribute, DepList);
|
||||
for (auto ei : out_edges) {
|
||||
edgeAttrMap[ei.second]["color"] = "red";
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#elif defined (__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
void markOutOfScopeLinks() {
|
||||
const boost::property_map<Graph, boost::edge_attribute_t>::type& edgeAttrMap = boost::get(boost::edge_attribute, DepList);
|
||||
void markOutOfScopeLinks()
|
||||
{
|
||||
const boost::property_map<Graph, boost::edge_attribute_t>::type& edgeAttrMap =
|
||||
boost::get(boost::edge_attribute, DepList);
|
||||
|
||||
for( auto obj : objects) {
|
||||
for (auto obj : objects) {
|
||||
|
||||
std::vector<App::DocumentObject*> invalids;
|
||||
GeoFeatureGroupExtension::getInvalidLinkObjects(obj, invalids);
|
||||
//isLinkValid returns true for non-link properties
|
||||
for(auto linkedObj : invalids) {
|
||||
// isLinkValid returns true for non-link properties
|
||||
for (auto linkedObj : invalids) {
|
||||
|
||||
auto res = edge(GlobalVertexList[getId(obj)], GlobalVertexList[getId(linkedObj)], DepList);
|
||||
if(res.second)
|
||||
auto res = edge(GlobalVertexList[getId(obj)],
|
||||
GlobalVertexList[getId(linkedObj)],
|
||||
DepList);
|
||||
if (res.second) {
|
||||
edgeAttrMap[res.first]["color"] = "orange";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const struct DocumentP* d;
|
||||
Graph DepList;
|
||||
int vertex_no{0};
|
||||
int vertex_no {0};
|
||||
std::map<std::string, Vertex> LocalVertexList;
|
||||
std::map<std::string, Vertex> GlobalVertexList;
|
||||
std::set<const DocumentObject*> objects;
|
||||
std::map<const DocumentObject*, Graph*> GraphList;
|
||||
//random color generation
|
||||
// random color generation
|
||||
std::mt19937 seed;
|
||||
std::uniform_int_distribution<int> distribution;
|
||||
};
|
||||
|
||||
@@ -35,21 +35,29 @@ namespace sp = std::placeholders;
|
||||
|
||||
EXTENSION_PROPERTY_SOURCE(App::GroupExtension, App::DocumentObjectExtension)
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
EXTENSION_PROPERTY_SOURCE_TEMPLATE(App::GroupExtensionPython, App::GroupExtension)
|
||||
|
||||
// explicit template instantiation
|
||||
template class AppExport ExtensionPythonT<GroupExtensionPythonT<GroupExtension>>;
|
||||
}
|
||||
} // namespace App
|
||||
|
||||
GroupExtension::GroupExtension()
|
||||
{
|
||||
initExtensionType(GroupExtension::getExtensionClassTypeId());
|
||||
|
||||
EXTENSION_ADD_PROPERTY_TYPE(Group,(nullptr),"Base",(App::PropertyType)(Prop_None),"List of referenced objects");
|
||||
|
||||
EXTENSION_ADD_PROPERTY_TYPE(_GroupTouched, (false), "Base",
|
||||
PropertyType(Prop_Hidden|Prop_Transient),0);
|
||||
EXTENSION_ADD_PROPERTY_TYPE(Group,
|
||||
(nullptr),
|
||||
"Base",
|
||||
(App::PropertyType)(Prop_None),
|
||||
"List of referenced objects");
|
||||
|
||||
EXTENSION_ADD_PROPERTY_TYPE(_GroupTouched,
|
||||
(false),
|
||||
"Base",
|
||||
PropertyType(Prop_Hidden | Prop_Transient),
|
||||
0);
|
||||
}
|
||||
|
||||
GroupExtension::~GroupExtension() = default;
|
||||
@@ -57,7 +65,7 @@ GroupExtension::~GroupExtension() = default;
|
||||
DocumentObject* GroupExtension::addObject(const char* sType, const char* pObjectName)
|
||||
{
|
||||
DocumentObject* obj = getExtendedObject()->getDocument()->addObject(sType, pObjectName);
|
||||
if(!allowObject(obj)) {
|
||||
if (!allowObject(obj)) {
|
||||
getExtendedObject()->getDocument()->removeObject(obj->getNameInDocument());
|
||||
return nullptr;
|
||||
}
|
||||
@@ -71,47 +79,55 @@ std::vector<DocumentObject*> GroupExtension::addObject(DocumentObject* obj)
|
||||
return addObjects(vec);
|
||||
}
|
||||
|
||||
std::vector< DocumentObject* > GroupExtension::addObjects(std::vector< DocumentObject* > objs) {
|
||||
|
||||
std::vector<DocumentObject*> GroupExtension::addObjects(std::vector<DocumentObject*> objs)
|
||||
{
|
||||
|
||||
std::vector<DocumentObject*> added;
|
||||
std::vector<DocumentObject*> grp = Group.getValues();
|
||||
for(auto obj : objs) {
|
||||
|
||||
if(!allowObject(obj))
|
||||
for (auto obj : objs) {
|
||||
|
||||
if (!allowObject(obj)) {
|
||||
continue;
|
||||
|
||||
if (hasObject(obj))
|
||||
}
|
||||
|
||||
if (hasObject(obj)) {
|
||||
continue;
|
||||
|
||||
//only one group per object. Note that it is allowed to be in a group and geofeaturegroup. However,
|
||||
//getGroupOfObject() returns only normal groups, no GeoFeatureGroups. Hence this works.
|
||||
auto *group = App::GroupExtension::getGroupOfObject(obj);
|
||||
if(group && group != getExtendedObject())
|
||||
}
|
||||
|
||||
// only one group per object. Note that it is allowed to be in a group and geofeaturegroup.
|
||||
// However, getGroupOfObject() returns only normal groups, no GeoFeatureGroups. Hence this
|
||||
// works.
|
||||
auto* group = App::GroupExtension::getGroupOfObject(obj);
|
||||
if (group && group != getExtendedObject()) {
|
||||
group->getExtensionByType<App::GroupExtension>()->removeObject(obj);
|
||||
|
||||
//if we are in a geofeaturegroup we need to ensure the object is too
|
||||
}
|
||||
|
||||
// if we are in a geofeaturegroup we need to ensure the object is too
|
||||
auto geogrp = GeoFeatureGroupExtension::getGroupOfObject(getExtendedObject());
|
||||
auto objgrp = GeoFeatureGroupExtension::getGroupOfObject(obj);
|
||||
if( geogrp != objgrp ) {
|
||||
//what to do depends on if we are in geofeature group or not
|
||||
if(geogrp)
|
||||
if (geogrp != objgrp) {
|
||||
// what to do depends on if we are in geofeature group or not
|
||||
if (geogrp) {
|
||||
geogrp->getExtensionByType<GeoFeatureGroupExtension>()->addObject(obj);
|
||||
else
|
||||
}
|
||||
else {
|
||||
objgrp->getExtensionByType<GeoFeatureGroupExtension>()->removeObject(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
grp.push_back(obj);
|
||||
added.push_back(obj);
|
||||
}
|
||||
|
||||
|
||||
Group.setValues(grp);
|
||||
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
std::vector< DocumentObject* > GroupExtension::setObjects(std::vector< DocumentObject* > obj) {
|
||||
std::vector<DocumentObject*> GroupExtension::setObjects(std::vector<DocumentObject*> obj)
|
||||
{
|
||||
|
||||
Group.setValues(std::vector< DocumentObject* > ());
|
||||
Group.setValues(std::vector<DocumentObject*>());
|
||||
return addObjects(obj);
|
||||
}
|
||||
|
||||
@@ -121,26 +137,27 @@ std::vector<DocumentObject*> GroupExtension::removeObject(DocumentObject* obj)
|
||||
return removeObjects(vec);
|
||||
}
|
||||
|
||||
std::vector< DocumentObject* > GroupExtension::removeObjects(std::vector< DocumentObject* > objs) {
|
||||
std::vector<DocumentObject*> GroupExtension::removeObjects(std::vector<DocumentObject*> objs)
|
||||
{
|
||||
|
||||
const std::vector<DocumentObject*> & grp = Group.getValues();
|
||||
const std::vector<DocumentObject*>& grp = Group.getValues();
|
||||
std::vector<DocumentObject*> newGrp = grp;
|
||||
std::vector<DocumentObject*> removed;
|
||||
|
||||
std::vector<DocumentObject*>::iterator end = newGrp.end();
|
||||
for(auto obj : objs) {
|
||||
auto res = std::remove(newGrp.begin(), end, obj);
|
||||
if(res != end) {
|
||||
end = res;
|
||||
removed.push_back(obj);
|
||||
}
|
||||
for (auto obj : objs) {
|
||||
auto res = std::remove(newGrp.begin(), end, obj);
|
||||
if (res != end) {
|
||||
end = res;
|
||||
removed.push_back(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
newGrp.erase(end, newGrp.end());
|
||||
if (grp.size() != newGrp.size()) {
|
||||
Group.setValues (newGrp);
|
||||
Group.setValues(newGrp);
|
||||
}
|
||||
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
@@ -150,7 +167,7 @@ void GroupExtension::removeObjectsFromDocument()
|
||||
// Remove the objects step by step because it can happen
|
||||
// that an object is part of several groups and thus a
|
||||
// double destruction could be possible
|
||||
const std::vector<DocumentObject*> & grp = Group.getValues();
|
||||
const std::vector<DocumentObject*>& grp = Group.getValues();
|
||||
removeObjectFromDocument(grp.front());
|
||||
}
|
||||
}
|
||||
@@ -158,12 +175,14 @@ void GroupExtension::removeObjectsFromDocument()
|
||||
void GroupExtension::removeObjectFromDocument(DocumentObject* obj)
|
||||
{
|
||||
// check that object is not invalid
|
||||
if (!obj || !obj->isAttachedToDocument())
|
||||
if (!obj || !obj->isAttachedToDocument()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove all children
|
||||
if (obj->hasExtension(GroupExtension::getExtensionClassTypeId())) {
|
||||
GroupExtension *grp = static_cast<GroupExtension*>(obj->getExtension(GroupExtension::getExtensionClassTypeId()));
|
||||
GroupExtension* grp = static_cast<GroupExtension*>(
|
||||
obj->getExtension(GroupExtension::getExtensionClassTypeId()));
|
||||
|
||||
// recursive call to remove all subgroups
|
||||
grp->removeObjectsFromDocument();
|
||||
@@ -172,11 +191,12 @@ void GroupExtension::removeObjectFromDocument(DocumentObject* obj)
|
||||
getExtendedObject()->getDocument()->removeObject(obj->getNameInDocument());
|
||||
}
|
||||
|
||||
DocumentObject *GroupExtension::getObject(const char *Name) const
|
||||
DocumentObject* GroupExtension::getObject(const char* Name) const
|
||||
{
|
||||
DocumentObject* obj = getExtendedObject()->getDocument()->getObject(Name);
|
||||
if (obj && hasObject(obj))
|
||||
if (obj && hasObject(obj)) {
|
||||
return obj;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -190,22 +210,24 @@ bool GroupExtension::hasObject(const DocumentObject* obj, bool recursive) const
|
||||
const std::vector<DocumentObject*>& grp = Group.getValues();
|
||||
for (auto child : grp) {
|
||||
|
||||
if (!child)
|
||||
if (!child) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (child == obj) {
|
||||
return true;
|
||||
}
|
||||
else if (child == getExtendedObject()) {
|
||||
throw Base::RuntimeError("Cyclic dependencies detected: Search cannot be performed");
|
||||
throw Base::RuntimeError(
|
||||
"Cyclic dependencies detected: Search cannot be performed");
|
||||
}
|
||||
else if ( recursive && child->hasExtension(GroupExtension::getExtensionClassTypeId()) ) {
|
||||
App::GroupExtension *subGroup = static_cast<App::GroupExtension *> (
|
||||
child->getExtension(GroupExtension::getExtensionClassTypeId()));
|
||||
else if (recursive && child->hasExtension(GroupExtension::getExtensionClassTypeId())) {
|
||||
App::GroupExtension* subGroup = static_cast<App::GroupExtension*>(
|
||||
child->getExtension(GroupExtension::getExtensionClassTypeId()));
|
||||
std::vector<const GroupExtension*> history;
|
||||
history.push_back(this);
|
||||
|
||||
if (subGroup->recursiveHasObject (obj, subGroup, history)) {
|
||||
if (subGroup->recursiveHasObject(obj, subGroup, history)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -219,31 +241,36 @@ bool GroupExtension::hasObject(const DocumentObject* obj, bool recursive) const
|
||||
}
|
||||
}
|
||||
|
||||
bool GroupExtension::recursiveHasObject(const DocumentObject* obj, const GroupExtension* group,
|
||||
std::vector< const GroupExtension* > history) const {
|
||||
bool GroupExtension::recursiveHasObject(const DocumentObject* obj,
|
||||
const GroupExtension* group,
|
||||
std::vector<const GroupExtension*> history) const
|
||||
{
|
||||
|
||||
//the purpose is to prevent infinite recursion when groups form a cyclic graph. To do this
|
||||
//we store every group we processed on the current leave of the tree, and if we reach an
|
||||
//already processed group we know that it not really is a tree but a cycle.
|
||||
// the purpose is to prevent infinite recursion when groups form a cyclic graph. To do this
|
||||
// we store every group we processed on the current leave of the tree, and if we reach an
|
||||
// already processed group we know that it not really is a tree but a cycle.
|
||||
history.push_back(this);
|
||||
|
||||
//we use hasObject with out recursion to allow override in derived classes
|
||||
if(group->hasObject(obj, false))
|
||||
// we use hasObject with out recursion to allow override in derived classes
|
||||
if (group->hasObject(obj, false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//we checked for the searched object already with hasObject and did not find it, now we need to
|
||||
//do the same for all subgroups
|
||||
// we checked for the searched object already with hasObject and did not find it, now we need to
|
||||
// do the same for all subgroups
|
||||
for (auto child : group->Group.getValues()) {
|
||||
|
||||
if(!child)
|
||||
if (!child) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( child->hasExtension(GroupExtension::getExtensionClassTypeId()) ) {
|
||||
if (child->hasExtension(GroupExtension::getExtensionClassTypeId())) {
|
||||
|
||||
auto ext = child->getExtensionByType<GroupExtension>();
|
||||
|
||||
|
||||
if (std::find(history.begin(), history.end(), ext) != history.end()) {
|
||||
throw Base::RuntimeError("Cyclic dependencies detected: Search cannot be performed");
|
||||
throw Base::RuntimeError(
|
||||
"Cyclic dependencies detected: Search cannot be performed");
|
||||
}
|
||||
|
||||
if (recursiveHasObject(obj, ext, history)) {
|
||||
@@ -259,7 +286,7 @@ bool GroupExtension::isChildOf(const GroupExtension* group, bool recursive) cons
|
||||
return group->hasObject(getExtendedObject(), recursive);
|
||||
}
|
||||
|
||||
const std::vector<DocumentObject*> &GroupExtension::getObjects() const
|
||||
const std::vector<DocumentObject*>& GroupExtension::getObjects() const
|
||||
{
|
||||
return Group.getValues();
|
||||
}
|
||||
@@ -269,8 +296,9 @@ std::vector<DocumentObject*> GroupExtension::getObjectsOfType(const Base::Type&
|
||||
std::vector<DocumentObject*> type;
|
||||
const std::vector<DocumentObject*>& grp = Group.getValues();
|
||||
for (auto it : grp) {
|
||||
if (it->getTypeId().isDerivedFrom(typeId))
|
||||
if (it->getTypeId().isDerivedFrom(typeId)) {
|
||||
type.push_back(it);
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
@@ -278,11 +306,12 @@ std::vector<DocumentObject*> GroupExtension::getObjectsOfType(const Base::Type&
|
||||
|
||||
int GroupExtension::countObjectsOfType(const Base::Type& typeId) const
|
||||
{
|
||||
int type=0;
|
||||
int type = 0;
|
||||
const std::vector<DocumentObject*>& grp = Group.getValues();
|
||||
for (auto it : grp) {
|
||||
if ( it->getTypeId().isDerivedFrom(typeId))
|
||||
if (it->getTypeId().isDerivedFrom(typeId)) {
|
||||
type++;
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
@@ -290,57 +319,63 @@ int GroupExtension::countObjectsOfType(const Base::Type& typeId) const
|
||||
|
||||
DocumentObject* GroupExtension::getGroupOfObject(const DocumentObject* obj)
|
||||
{
|
||||
//note that we return here only Groups, but nothing derived from it, e.g. no GeoFeatureGroups.
|
||||
//That is important as there are clear differences between groups/geofeature groups (e.g. an object
|
||||
//can be in only one group, and only one geofeaturegroup, however, it can be in both at the same time)
|
||||
// note that we return here only Groups, but nothing derived from it, e.g. no GeoFeatureGroups.
|
||||
// That is important as there are clear differences between groups/geofeature groups (e.g. an
|
||||
// object can be in only one group, and only one geofeaturegroup, however, it can be in both at
|
||||
// the same time)
|
||||
for (auto o : obj->getInList()) {
|
||||
if (o->hasExtension(App::GroupExtension::getExtensionClassTypeId(), false))
|
||||
if (o->hasExtension(App::GroupExtension::getExtensionClassTypeId(), false)) {
|
||||
return o;
|
||||
if (o->hasExtension(App::GroupExtensionPython::getExtensionClassTypeId(), false))
|
||||
}
|
||||
if (o->hasExtension(App::GroupExtensionPython::getExtensionClassTypeId(), false)) {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PyObject* GroupExtension::getExtensionPyObject() {
|
||||
PyObject* GroupExtension::getExtensionPyObject()
|
||||
{
|
||||
|
||||
if (ExtensionPythonObject.is(Py::_None())){
|
||||
if (ExtensionPythonObject.is(Py::_None())) {
|
||||
// ref counter is set to 1
|
||||
auto grp = new GroupExtensionPy(this);
|
||||
ExtensionPythonObject = Py::Object(grp,true);
|
||||
ExtensionPythonObject = Py::Object(grp, true);
|
||||
}
|
||||
return Py::new_reference_to(ExtensionPythonObject);
|
||||
}
|
||||
|
||||
void GroupExtension::extensionOnChanged(const Property* p) {
|
||||
void GroupExtension::extensionOnChanged(const Property* p)
|
||||
{
|
||||
|
||||
// objects are only allowed in a single group. Note that this check must only be done for normal
|
||||
// groups, not any derived classes
|
||||
if ((this->getExtensionTypeId() == GroupExtension::getExtensionClassTypeId()) && p == &Group
|
||||
&& !Group.testStatus(Property::User3)) {
|
||||
if (!getExtendedObject()->isRestoring()
|
||||
&& !getExtendedObject()->getDocument()->isPerformingTransaction()) {
|
||||
|
||||
//objects are only allowed in a single group. Note that this check must only be done for normal
|
||||
//groups, not any derived classes
|
||||
if((this->getExtensionTypeId() == GroupExtension::getExtensionClassTypeId())
|
||||
&& p == &Group && !Group.testStatus(Property::User3))
|
||||
{
|
||||
if(!getExtendedObject()->isRestoring() &&
|
||||
!getExtendedObject()->getDocument()->isPerformingTransaction()) {
|
||||
|
||||
bool error = false;
|
||||
auto corrected = Group.getValues();
|
||||
for(auto obj : Group.getValues()) {
|
||||
for (auto obj : Group.getValues()) {
|
||||
|
||||
//we have already set the obj into the group, so in a case of multiple groups getGroupOfObject
|
||||
//would return anyone of it and hence it is possible that we miss an error. We need a custom check
|
||||
// we have already set the obj into the group, so in a case of multiple groups
|
||||
// getGroupOfObject would return anyone of it and hence it is possible that we miss
|
||||
// an error. We need a custom check
|
||||
auto list = obj->getInList();
|
||||
for (auto in : list) {
|
||||
if(in->hasExtension(App::GroupExtension::getExtensionClassTypeId(), false) &&
|
||||
in != getExtendedObject()) {
|
||||
if (in->hasExtension(App::GroupExtension::getExtensionClassTypeId(), false)
|
||||
&& in != getExtendedObject()) {
|
||||
error = true;
|
||||
corrected.erase(std::remove(corrected.begin(), corrected.end(), obj), corrected.end());
|
||||
corrected.erase(std::remove(corrected.begin(), corrected.end(), obj),
|
||||
corrected.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if an error was found we need to correct the values and inform the user
|
||||
if(error) {
|
||||
// if an error was found we need to correct the values and inform the user
|
||||
if (error) {
|
||||
Base::ObjectStatusLocker<Property::Status, Property> guard(Property::User3, &Group);
|
||||
Group.setValues(corrected);
|
||||
throw Base::RuntimeError("Object can only be in a single Group");
|
||||
@@ -348,14 +383,14 @@ void GroupExtension::extensionOnChanged(const Property* p) {
|
||||
}
|
||||
}
|
||||
|
||||
if(p == &Group) {
|
||||
if (p == &Group) {
|
||||
_Conns.clear();
|
||||
for(auto obj : Group.getValue()) {
|
||||
if(obj && obj->isAttachedToDocument()) {
|
||||
//NOLINTBEGIN
|
||||
_Conns[obj] = obj->signalChanged.connect(std::bind(
|
||||
&GroupExtension::slotChildChanged,this,sp::_1, sp::_2));
|
||||
//NOLINTEND
|
||||
for (auto obj : Group.getValue()) {
|
||||
if (obj && obj->isAttachedToDocument()) {
|
||||
// NOLINTBEGIN
|
||||
_Conns[obj] = obj->signalChanged.connect(
|
||||
std::bind(&GroupExtension::slotChildChanged, this, sp::_1, sp::_2));
|
||||
// NOLINTEND
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -363,71 +398,87 @@ void GroupExtension::extensionOnChanged(const Property* p) {
|
||||
App::Extension::extensionOnChanged(p);
|
||||
}
|
||||
|
||||
void GroupExtension::slotChildChanged(const DocumentObject &obj, const Property &prop) {
|
||||
if(&prop == &obj.Visibility)
|
||||
void GroupExtension::slotChildChanged(const DocumentObject& obj, const Property& prop)
|
||||
{
|
||||
if (&prop == &obj.Visibility) {
|
||||
_GroupTouched.touch();
|
||||
}
|
||||
}
|
||||
|
||||
bool GroupExtension::extensionGetSubObject(DocumentObject *&ret, const char *subname,
|
||||
PyObject **pyObj, Base::Matrix4D *mat, bool /*transform*/, int depth) const
|
||||
bool GroupExtension::extensionGetSubObject(DocumentObject*& ret,
|
||||
const char* subname,
|
||||
PyObject** pyObj,
|
||||
Base::Matrix4D* mat,
|
||||
bool /*transform*/,
|
||||
int depth) const
|
||||
{
|
||||
const char *dot;
|
||||
if(!subname || *subname==0) {
|
||||
const char* dot;
|
||||
if (!subname || *subname == 0) {
|
||||
auto obj = Base::freecad_dynamic_cast<const DocumentObject>(getExtendedContainer());
|
||||
ret = const_cast<DocumentObject*>(obj);
|
||||
return true;
|
||||
}
|
||||
dot=strchr(subname,'.');
|
||||
if(!dot)
|
||||
dot = strchr(subname, '.');
|
||||
if (!dot) {
|
||||
return false;
|
||||
if(subname[0]!='$')
|
||||
ret = Group.findUsingMap(std::string(subname,dot));
|
||||
else{
|
||||
std::string name = std::string(subname+1,dot);
|
||||
for(auto child : Group.getValues()) {
|
||||
if(name == child->Label.getStrValue()){
|
||||
}
|
||||
if (subname[0] != '$') {
|
||||
ret = Group.findUsingMap(std::string(subname, dot));
|
||||
}
|
||||
else {
|
||||
std::string name = std::string(subname + 1, dot);
|
||||
for (auto child : Group.getValues()) {
|
||||
if (name == child->Label.getStrValue()) {
|
||||
ret = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!ret)
|
||||
if (!ret) {
|
||||
return false;
|
||||
return ret->getSubObject(dot+1,pyObj,mat,true,depth+1);
|
||||
}
|
||||
return ret->getSubObject(dot + 1, pyObj, mat, true, depth + 1);
|
||||
}
|
||||
|
||||
bool GroupExtension::extensionGetSubObjects(std::vector<std::string> &ret, int) const {
|
||||
for(auto obj : Group.getValues()) {
|
||||
if(obj && obj->isAttachedToDocument())
|
||||
ret.push_back(std::string(obj->getNameInDocument())+'.');
|
||||
bool GroupExtension::extensionGetSubObjects(std::vector<std::string>& ret, int) const
|
||||
{
|
||||
for (auto obj : Group.getValues()) {
|
||||
if (obj && obj->isAttachedToDocument()) {
|
||||
ret.push_back(std::string(obj->getNameInDocument()) + '.');
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
App::DocumentObjectExecReturn *GroupExtension::extensionExecute() {
|
||||
App::DocumentObjectExecReturn* GroupExtension::extensionExecute()
|
||||
{
|
||||
// This touch property is for propagating changes to upper group
|
||||
_GroupTouched.touch();
|
||||
return inherited::extensionExecute();
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> GroupExtension::getAllChildren() const {
|
||||
std::vector<App::DocumentObject*> GroupExtension::getAllChildren() const
|
||||
{
|
||||
std::vector<DocumentObject*> res;
|
||||
std::set<DocumentObject*> rset;
|
||||
getAllChildren(res,rset);
|
||||
getAllChildren(res, rset);
|
||||
return res;
|
||||
}
|
||||
|
||||
void GroupExtension::getAllChildren(std::vector<App::DocumentObject*> &res,
|
||||
std::set<App::DocumentObject*> &rset) const
|
||||
void GroupExtension::getAllChildren(std::vector<App::DocumentObject*>& res,
|
||||
std::set<App::DocumentObject*>& rset) const
|
||||
{
|
||||
for(auto obj : Group.getValues()) {
|
||||
if(!obj || !obj->isAttachedToDocument())
|
||||
for (auto obj : Group.getValues()) {
|
||||
if (!obj || !obj->isAttachedToDocument()) {
|
||||
continue;
|
||||
if(!rset.insert(obj).second)
|
||||
}
|
||||
if (!rset.insert(obj).second) {
|
||||
continue;
|
||||
}
|
||||
res.push_back(obj);
|
||||
auto ext = obj->getExtensionByType<GroupExtension>(true,false);
|
||||
if(ext)
|
||||
ext->getAllChildren(res,rset);
|
||||
auto ext = obj->getExtensionByType<GroupExtension>(true, false);
|
||||
if (ext) {
|
||||
ext->getAllChildren(res, rset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace App
|
||||
class DocumentObjectGroup;
|
||||
class GroupExtensionPy;
|
||||
|
||||
class AppExport GroupExtension : public DocumentObjectExtension
|
||||
class AppExport GroupExtension: public DocumentObjectExtension
|
||||
{
|
||||
EXTENSION_PROPERTY_HEADER_WITH_OVERRIDE(App::GroupExtension);
|
||||
using inherited = DocumentObjectExtension;
|
||||
@@ -50,22 +50,25 @@ public:
|
||||
/** Adds an object of \a sType with \a pObjectName to the document this group belongs to and
|
||||
* append it to this group as well.
|
||||
*/
|
||||
virtual DocumentObject *addObject(const char* sType, const char* pObjectName);
|
||||
virtual DocumentObject* addObject(const char* sType, const char* pObjectName);
|
||||
/* Adds the object \a obj to this group. Returns all objects that have been added.
|
||||
*/
|
||||
virtual std::vector<DocumentObject*> addObject(DocumentObject* obj);
|
||||
/* Adds the objects \a objs to this group. Returns all objects that have been added.
|
||||
*/
|
||||
virtual std::vector<DocumentObject*> addObjects(std::vector<DocumentObject*> obj);
|
||||
|
||||
|
||||
/* Sets the objects in this group. Everything contained already will be removed first
|
||||
*/
|
||||
virtual std::vector< DocumentObject* > setObjects(std::vector< DocumentObject* > obj);
|
||||
|
||||
virtual std::vector<DocumentObject*> setObjects(std::vector<DocumentObject*> obj);
|
||||
|
||||
/*override this function if you want only special objects
|
||||
*/
|
||||
virtual bool allowObject(DocumentObject* ) {return true;}
|
||||
|
||||
virtual bool allowObject(DocumentObject*)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Removes an object from this group. Returns all objects that have been removed.
|
||||
*/
|
||||
virtual std::vector<DocumentObject*> removeObject(DocumentObject* obj);
|
||||
@@ -75,16 +78,19 @@ public:
|
||||
/** Removes all children objects from this group and the document.
|
||||
*/
|
||||
virtual void removeObjectsFromDocument();
|
||||
/** Returns the object of this group with \a Name. If the group doesn't have such an object 0 is returned.
|
||||
* @note This method might return 0 even if the document this group belongs to contains an object with this name.
|
||||
/** Returns the object of this group with \a Name. If the group doesn't have such an object 0 is
|
||||
* returned.
|
||||
* @note This method might return 0 even if the document this group belongs to contains an
|
||||
* object with this name.
|
||||
*/
|
||||
DocumentObject *getObject(const char* Name) const;
|
||||
DocumentObject* getObject(const char* Name) const;
|
||||
/**
|
||||
* Checks whether the object \a obj is part of this group.
|
||||
* @param obj the object to check for.
|
||||
* @param recursive if true check also if the obj is child of some sub group (default is false).
|
||||
* @param recursive if true check also if the obj is child of some sub group (default is
|
||||
* false).
|
||||
*/
|
||||
virtual bool hasObject(const DocumentObject* obj, bool recursive=false) const;
|
||||
virtual bool hasObject(const DocumentObject* obj, bool recursive = false) const;
|
||||
/**
|
||||
* Checks whether this group object is a child (or sub-child if enabled)
|
||||
* of the given group object.
|
||||
@@ -92,7 +98,7 @@ public:
|
||||
bool isChildOf(const GroupExtension* group, bool recursive = true) const;
|
||||
/** Returns a list of all objects this group does have.
|
||||
*/
|
||||
const std::vector<DocumentObject*> &getObjects() const;
|
||||
const std::vector<DocumentObject*>& getObjects() const;
|
||||
/** Returns a list of all objects of \a typeId this group does have.
|
||||
*/
|
||||
std::vector<DocumentObject*> getObjectsOfType(const Base::Type& typeId) const;
|
||||
@@ -100,36 +106,44 @@ public:
|
||||
*/
|
||||
int countObjectsOfType(const Base::Type& typeId) const;
|
||||
/** Returns the object group of the document which the given object \a obj is part of.
|
||||
* In case this object is not part of a group 0 is returned.
|
||||
* @note This only returns objects that are normal groups, not any special derived type
|
||||
* like GeoFeatureGroups or OriginGroups. To retrieve those please use their appropriate functions
|
||||
* In case this object is not part of a group 0 is returned.
|
||||
* @note This only returns objects that are normal groups, not any special derived type
|
||||
* like GeoFeatureGroups or OriginGroups. To retrieve those please use their appropriate
|
||||
* functions
|
||||
*/
|
||||
static DocumentObject* getGroupOfObject(const DocumentObject* obj);
|
||||
//@}
|
||||
|
||||
|
||||
PyObject* getExtensionPyObject() override;
|
||||
|
||||
void extensionOnChanged(const Property* p) override;
|
||||
|
||||
bool extensionGetSubObject(DocumentObject *&ret, const char *subname,
|
||||
PyObject **pyObj, Base::Matrix4D *mat, bool transform, int depth) const override;
|
||||
bool extensionGetSubObject(DocumentObject*& ret,
|
||||
const char* subname,
|
||||
PyObject** pyObj,
|
||||
Base::Matrix4D* mat,
|
||||
bool transform,
|
||||
int depth) const override;
|
||||
|
||||
bool extensionGetSubObjects(std::vector<std::string> &ret, int reason) const override;
|
||||
bool extensionGetSubObjects(std::vector<std::string>& ret, int reason) const override;
|
||||
|
||||
App::DocumentObjectExecReturn *extensionExecute() override;
|
||||
App::DocumentObjectExecReturn* extensionExecute() override;
|
||||
|
||||
std::vector<DocumentObject*> getAllChildren() const;
|
||||
void getAllChildren(std::vector<DocumentObject*> &, std::set<DocumentObject*> &) const;
|
||||
|
||||
void getAllChildren(std::vector<DocumentObject*>&, std::set<DocumentObject*>&) const;
|
||||
|
||||
/// Properties
|
||||
PropertyLinkList Group;
|
||||
PropertyBool _GroupTouched;
|
||||
|
||||
private:
|
||||
void removeObjectFromDocument(DocumentObject*);
|
||||
// This function stores the already searched objects to prevent infinite recursion in case of a cyclic group graph
|
||||
// It throws an exception of type Base::RuntimeError if a cyclic dependency is detected.
|
||||
bool recursiveHasObject(const DocumentObject* obj, const GroupExtension* group, std::vector<const GroupExtension*> history) const;
|
||||
// This function stores the already searched objects to prevent infinite recursion in case of a
|
||||
// cyclic group graph It throws an exception of type Base::RuntimeError if a cyclic dependency
|
||||
// is detected.
|
||||
bool recursiveHasObject(const DocumentObject* obj,
|
||||
const GroupExtension* group,
|
||||
std::vector<const GroupExtension*> history) const;
|
||||
|
||||
// for tracking children visibility
|
||||
void slotChildChanged(const App::DocumentObject&, const App::Property&);
|
||||
@@ -138,32 +152,35 @@ private:
|
||||
|
||||
|
||||
template<typename ExtensionT>
|
||||
class GroupExtensionPythonT : public ExtensionT {
|
||||
|
||||
class GroupExtensionPythonT: public ExtensionT
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
GroupExtensionPythonT() = default;
|
||||
~GroupExtensionPythonT() override = default;
|
||||
|
||||
//override the documentobjectextension functions to make them available in python
|
||||
bool allowObject(DocumentObject* obj) override {
|
||||
|
||||
// override the documentobjectextension functions to make them available in python
|
||||
bool allowObject(DocumentObject* obj) override
|
||||
{
|
||||
Base::PyGILStateLocker locker;
|
||||
Py::Object pyobj = Py::asObject(obj->getPyObject());
|
||||
EXTENSION_PROXY_ONEARG(allowObject, pyobj);
|
||||
|
||||
if(result.isNone())
|
||||
|
||||
if (result.isNone()) {
|
||||
return ExtensionT::allowObject(obj);
|
||||
|
||||
if(result.isBoolean())
|
||||
}
|
||||
|
||||
if (result.isBoolean()) {
|
||||
return result.isTrue();
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
};
|
||||
|
||||
using GroupExtensionPython = ExtensionPythonT<GroupExtensionPythonT<GroupExtension>>;
|
||||
|
||||
} //namespace App
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // APP_GROUPEXTENSION_H
|
||||
#endif // APP_GROUPEXTENSION_H
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="DocumentObjectExtensionPy"
|
||||
Name="GroupExtensionPy"
|
||||
Twin="GroupExtension"
|
||||
TwinPointer="GroupExtension"
|
||||
Include="App/DocumentObjectGroup.h"
|
||||
Namespace="App"
|
||||
FatherInclude="App/DocumentObjectExtensionPy.h"
|
||||
<PythonExport
|
||||
Father="DocumentObjectExtensionPy"
|
||||
Name="GroupExtensionPy"
|
||||
Twin="GroupExtension"
|
||||
TwinPointer="GroupExtension"
|
||||
Include="App/DocumentObjectGroup.h"
|
||||
Namespace="App"
|
||||
FatherInclude="App/DocumentObjectExtensionPy.h"
|
||||
FatherNamespace="App">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Werner Mayer" EMail="wmayer@users.sourceforge.net" />
|
||||
|
||||
@@ -39,14 +39,15 @@ std::string GroupExtensionPy::representation() const
|
||||
return {"<group extension object>"};
|
||||
}
|
||||
|
||||
PyObject* GroupExtensionPy::newObject(PyObject *args)
|
||||
PyObject* GroupExtensionPy::newObject(PyObject* args)
|
||||
{
|
||||
char *sType,*sName=nullptr;
|
||||
if (!PyArg_ParseTuple(args, "s|s", &sType,&sName))
|
||||
char *sType, *sName = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "s|s", &sType, &sName)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DocumentObject *object = getGroupExtensionPtr()->addObject(sType, sName);
|
||||
if ( object ) {
|
||||
DocumentObject* object = getGroupExtensionPtr()->addObject(sType, sName);
|
||||
if (object) {
|
||||
return object->getPyObject();
|
||||
}
|
||||
else {
|
||||
@@ -55,20 +56,24 @@ PyObject* GroupExtensionPy::newObject(PyObject *args)
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* GroupExtensionPy::addObject(PyObject *args)
|
||||
PyObject* GroupExtensionPy::addObject(PyObject* args)
|
||||
{
|
||||
PyObject *object;
|
||||
if (!PyArg_ParseTuple(args, "O!", &(DocumentObjectPy::Type), &object))
|
||||
PyObject* object;
|
||||
if (!PyArg_ParseTuple(args, "O!", &(DocumentObjectPy::Type), &object)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DocumentObjectPy* docObj = static_cast<DocumentObjectPy*>(object);
|
||||
if (!docObj->getDocumentObjectPtr() || !docObj->getDocumentObjectPtr()->isAttachedToDocument()) {
|
||||
if (!docObj->getDocumentObjectPtr()
|
||||
|| !docObj->getDocumentObjectPtr()->isAttachedToDocument()) {
|
||||
PyErr_SetString(Base::PyExc_FC_GeneralError, "Cannot add an invalid object");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (docObj->getDocumentObjectPtr()->getDocument() != getGroupExtensionPtr()->getExtendedObject()->getDocument()) {
|
||||
PyErr_SetString(Base::PyExc_FC_GeneralError, "Cannot add an object from another document to this group");
|
||||
|
||||
if (docObj->getDocumentObjectPtr()->getDocument()
|
||||
!= getGroupExtensionPtr()->getExtendedObject()->getDocument()) {
|
||||
PyErr_SetString(Base::PyExc_FC_GeneralError,
|
||||
"Cannot add an object from another document to this group");
|
||||
return nullptr;
|
||||
}
|
||||
if (docObj->getDocumentObjectPtr() == this->getGroupExtensionPtr()->getExtendedObject()) {
|
||||
@@ -76,110 +81,123 @@ PyObject* GroupExtensionPy::addObject(PyObject *args)
|
||||
return nullptr;
|
||||
}
|
||||
if (docObj->getDocumentObjectPtr()->hasExtension(GroupExtension::getExtensionClassTypeId())) {
|
||||
App::GroupExtension* docGrp = docObj->getDocumentObjectPtr()->getExtensionByType<GroupExtension>();
|
||||
App::GroupExtension* docGrp =
|
||||
docObj->getDocumentObjectPtr()->getExtensionByType<GroupExtension>();
|
||||
if (docGrp->hasObject(getGroupExtensionPtr()->getExtendedObject())) {
|
||||
PyErr_SetString(Base::PyExc_FC_GeneralError, "Cannot add a group object to a child group");
|
||||
PyErr_SetString(Base::PyExc_FC_GeneralError,
|
||||
"Cannot add a group object to a child group");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
GroupExtension* grp = getGroupExtensionPtr();
|
||||
|
||||
auto vec = grp->addObject(docObj->getDocumentObjectPtr());
|
||||
auto vec = grp->addObject(docObj->getDocumentObjectPtr());
|
||||
Py::List list;
|
||||
for (App::DocumentObject* obj : vec)
|
||||
for (App::DocumentObject* obj : vec) {
|
||||
list.append(Py::asObject(obj->getPyObject()));
|
||||
}
|
||||
|
||||
return Py::new_reference_to(list);
|
||||
}
|
||||
|
||||
PyObject* GroupExtensionPy::addObjects(PyObject *args) {
|
||||
|
||||
PyObject *object;
|
||||
if (!PyArg_ParseTuple(args, "O", &object))
|
||||
return nullptr;
|
||||
|
||||
if (PyTuple_Check(object) || PyList_Check(object)) {
|
||||
Py::Sequence list(object);
|
||||
Py::Sequence::size_type size = list.size();
|
||||
std::vector<DocumentObject*> values;
|
||||
values.resize(size);
|
||||
|
||||
for (Py::Sequence::size_type i = 0; i < size; i++) {
|
||||
Py::Object item = list[i];
|
||||
if (!PyObject_TypeCheck(*item, &(DocumentObjectPy::Type))) {
|
||||
std::string error = std::string("type in list must be 'DocumentObject', not ");
|
||||
error += (*item)->ob_type->tp_name;
|
||||
throw Base::TypeError(error);
|
||||
}
|
||||
|
||||
values[i] = static_cast<DocumentObjectPy*>(*item)->getDocumentObjectPtr();
|
||||
}
|
||||
|
||||
GroupExtension* grp = getGroupExtensionPtr();
|
||||
auto vec = grp->addObjects(values);
|
||||
Py::List result;
|
||||
for (App::DocumentObject* obj : vec)
|
||||
result.append(Py::asObject(obj->getPyObject()));
|
||||
|
||||
return Py::new_reference_to(result);
|
||||
}
|
||||
|
||||
std::string error = std::string("type must be list of 'DocumentObject', not ");
|
||||
error += object->ob_type->tp_name;
|
||||
throw Base::TypeError(error);
|
||||
}
|
||||
|
||||
PyObject* GroupExtensionPy::setObjects(PyObject *args) {
|
||||
|
||||
PyObject *object;
|
||||
if (!PyArg_ParseTuple(args, "O", &object))
|
||||
return nullptr;
|
||||
|
||||
if (PyTuple_Check(object) || PyList_Check(object)) {
|
||||
Py::Sequence list(object);
|
||||
Py::Sequence::size_type size = list.size();
|
||||
std::vector<DocumentObject*> values;
|
||||
values.resize(size);
|
||||
|
||||
for (Py::Sequence::size_type i = 0; i < size; i++) {
|
||||
Py::Object item = list[i];
|
||||
if (!PyObject_TypeCheck(*item, &(DocumentObjectPy::Type))) {
|
||||
std::string error = std::string("type in list must be 'DocumentObject', not ");
|
||||
error += (*item)->ob_type->tp_name;
|
||||
throw Base::TypeError(error);
|
||||
}
|
||||
|
||||
values[i] = static_cast<DocumentObjectPy*>(*item)->getDocumentObjectPtr();
|
||||
}
|
||||
|
||||
GroupExtension* grp = getGroupExtensionPtr();
|
||||
auto vec = grp->setObjects(values);
|
||||
Py::List result;
|
||||
for (App::DocumentObject* obj : vec)
|
||||
result.append(Py::asObject(obj->getPyObject()));
|
||||
|
||||
return Py::new_reference_to(result);
|
||||
}
|
||||
|
||||
std::string error = std::string("type must be list of 'DocumentObject', not ");
|
||||
error += object->ob_type->tp_name;
|
||||
throw Base::TypeError(error);
|
||||
}
|
||||
|
||||
PyObject* GroupExtensionPy::removeObject(PyObject *args)
|
||||
PyObject* GroupExtensionPy::addObjects(PyObject* args)
|
||||
{
|
||||
PyObject *object;
|
||||
if (!PyArg_ParseTuple(args, "O!", &(DocumentObjectPy::Type), &object))
|
||||
|
||||
PyObject* object;
|
||||
if (!PyArg_ParseTuple(args, "O", &object)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (PyTuple_Check(object) || PyList_Check(object)) {
|
||||
Py::Sequence list(object);
|
||||
Py::Sequence::size_type size = list.size();
|
||||
std::vector<DocumentObject*> values;
|
||||
values.resize(size);
|
||||
|
||||
for (Py::Sequence::size_type i = 0; i < size; i++) {
|
||||
Py::Object item = list[i];
|
||||
if (!PyObject_TypeCheck(*item, &(DocumentObjectPy::Type))) {
|
||||
std::string error = std::string("type in list must be 'DocumentObject', not ");
|
||||
error += (*item)->ob_type->tp_name;
|
||||
throw Base::TypeError(error);
|
||||
}
|
||||
|
||||
values[i] = static_cast<DocumentObjectPy*>(*item)->getDocumentObjectPtr();
|
||||
}
|
||||
|
||||
GroupExtension* grp = getGroupExtensionPtr();
|
||||
auto vec = grp->addObjects(values);
|
||||
Py::List result;
|
||||
for (App::DocumentObject* obj : vec) {
|
||||
result.append(Py::asObject(obj->getPyObject()));
|
||||
}
|
||||
|
||||
return Py::new_reference_to(result);
|
||||
}
|
||||
|
||||
std::string error = std::string("type must be list of 'DocumentObject', not ");
|
||||
error += object->ob_type->tp_name;
|
||||
throw Base::TypeError(error);
|
||||
}
|
||||
|
||||
PyObject* GroupExtensionPy::setObjects(PyObject* args)
|
||||
{
|
||||
|
||||
PyObject* object;
|
||||
if (!PyArg_ParseTuple(args, "O", &object)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (PyTuple_Check(object) || PyList_Check(object)) {
|
||||
Py::Sequence list(object);
|
||||
Py::Sequence::size_type size = list.size();
|
||||
std::vector<DocumentObject*> values;
|
||||
values.resize(size);
|
||||
|
||||
for (Py::Sequence::size_type i = 0; i < size; i++) {
|
||||
Py::Object item = list[i];
|
||||
if (!PyObject_TypeCheck(*item, &(DocumentObjectPy::Type))) {
|
||||
std::string error = std::string("type in list must be 'DocumentObject', not ");
|
||||
error += (*item)->ob_type->tp_name;
|
||||
throw Base::TypeError(error);
|
||||
}
|
||||
|
||||
values[i] = static_cast<DocumentObjectPy*>(*item)->getDocumentObjectPtr();
|
||||
}
|
||||
|
||||
GroupExtension* grp = getGroupExtensionPtr();
|
||||
auto vec = grp->setObjects(values);
|
||||
Py::List result;
|
||||
for (App::DocumentObject* obj : vec) {
|
||||
result.append(Py::asObject(obj->getPyObject()));
|
||||
}
|
||||
|
||||
return Py::new_reference_to(result);
|
||||
}
|
||||
|
||||
std::string error = std::string("type must be list of 'DocumentObject', not ");
|
||||
error += object->ob_type->tp_name;
|
||||
throw Base::TypeError(error);
|
||||
}
|
||||
|
||||
PyObject* GroupExtensionPy::removeObject(PyObject* args)
|
||||
{
|
||||
PyObject* object;
|
||||
if (!PyArg_ParseTuple(args, "O!", &(DocumentObjectPy::Type), &object)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DocumentObjectPy* docObj = static_cast<DocumentObjectPy*>(object);
|
||||
if (!docObj->getDocumentObjectPtr() || !docObj->getDocumentObjectPtr()->isAttachedToDocument()) {
|
||||
if (!docObj->getDocumentObjectPtr()
|
||||
|| !docObj->getDocumentObjectPtr()->isAttachedToDocument()) {
|
||||
PyErr_SetString(Base::PyExc_FC_GeneralError, "Cannot remove an invalid object");
|
||||
return nullptr;
|
||||
}
|
||||
if (docObj->getDocumentObjectPtr()->getDocument() != getGroupExtensionPtr()->getExtendedObject()->getDocument()) {
|
||||
PyErr_SetString(Base::PyExc_FC_GeneralError, "Cannot remove an object from another document from this group");
|
||||
if (docObj->getDocumentObjectPtr()->getDocument()
|
||||
!= getGroupExtensionPtr()->getExtendedObject()->getDocument()) {
|
||||
PyErr_SetString(Base::PyExc_FC_GeneralError,
|
||||
"Cannot remove an object from another document from this group");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -187,18 +205,21 @@ PyObject* GroupExtensionPy::removeObject(PyObject *args)
|
||||
|
||||
auto vec = grp->removeObject(docObj->getDocumentObjectPtr());
|
||||
Py::List list;
|
||||
for (App::DocumentObject* obj : vec)
|
||||
for (App::DocumentObject* obj : vec) {
|
||||
list.append(Py::asObject(obj->getPyObject()));
|
||||
}
|
||||
|
||||
return Py::new_reference_to(list);
|
||||
}
|
||||
|
||||
PyObject* GroupExtensionPy::removeObjects(PyObject *args) {
|
||||
PyObject* GroupExtensionPy::removeObjects(PyObject* args)
|
||||
{
|
||||
|
||||
PyObject *object;
|
||||
if (!PyArg_ParseTuple(args, "O", &object))
|
||||
PyObject* object;
|
||||
if (!PyArg_ParseTuple(args, "O", &object)) {
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
if (PyTuple_Check(object) || PyList_Check(object)) {
|
||||
Py::Sequence list(object);
|
||||
Py::Sequence::size_type size = list.size();
|
||||
@@ -217,10 +238,11 @@ PyObject* GroupExtensionPy::removeObjects(PyObject *args) {
|
||||
}
|
||||
|
||||
GroupExtension* grp = getGroupExtensionPtr();
|
||||
auto vec = grp->removeObjects(values);
|
||||
auto vec = grp->removeObjects(values);
|
||||
Py::List result;
|
||||
for (App::DocumentObject* obj : vec)
|
||||
for (App::DocumentObject* obj : vec) {
|
||||
result.append(Py::asObject(obj->getPyObject()));
|
||||
}
|
||||
|
||||
return Py::new_reference_to(result);
|
||||
}
|
||||
@@ -230,44 +252,56 @@ PyObject* GroupExtensionPy::removeObjects(PyObject *args) {
|
||||
throw Base::TypeError(error);
|
||||
}
|
||||
|
||||
PyObject* GroupExtensionPy::removeObjectsFromDocument(PyObject *args)
|
||||
PyObject* GroupExtensionPy::removeObjectsFromDocument(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
getGroupExtensionPtr()->removeObjectsFromDocument();
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* GroupExtensionPy::getObject(PyObject *args)
|
||||
PyObject* GroupExtensionPy::getObject(PyObject* args)
|
||||
{
|
||||
char* pcName;
|
||||
if (!PyArg_ParseTuple(args, "s", &pcName))
|
||||
if (!PyArg_ParseTuple(args, "s", &pcName)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DocumentObject* obj = getGroupExtensionPtr()->getObject(pcName);
|
||||
if ( obj ) {
|
||||
if (obj) {
|
||||
return obj->getPyObject();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Py_Return;
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* GroupExtensionPy::hasObject(PyObject *args)
|
||||
PyObject* GroupExtensionPy::hasObject(PyObject* args)
|
||||
{
|
||||
PyObject *object;
|
||||
PyObject *recursivePy = Py_False;
|
||||
if (!PyArg_ParseTuple(args, "O!|O!", &(DocumentObjectPy::Type), &object, &PyBool_Type, &recursivePy))
|
||||
PyObject* object;
|
||||
PyObject* recursivePy = Py_False;
|
||||
if (!PyArg_ParseTuple(args,
|
||||
"O!|O!",
|
||||
&(DocumentObjectPy::Type),
|
||||
&object,
|
||||
&PyBool_Type,
|
||||
&recursivePy)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DocumentObjectPy* docObj = static_cast<DocumentObjectPy*>(object);
|
||||
bool recursive = Base::asBoolean(recursivePy);
|
||||
if (!docObj->getDocumentObjectPtr() || !docObj->getDocumentObjectPtr()->isAttachedToDocument()) {
|
||||
if (!docObj->getDocumentObjectPtr()
|
||||
|| !docObj->getDocumentObjectPtr()->isAttachedToDocument()) {
|
||||
PyErr_SetString(Base::PyExc_FC_GeneralError, "Cannot check an invalid object");
|
||||
return nullptr;
|
||||
}
|
||||
if (docObj->getDocumentObjectPtr()->getDocument() != getGroupExtensionPtr()->getExtendedObject()->getDocument()) {
|
||||
PyErr_SetString(Base::PyExc_FC_GeneralError, "Cannot check an object from another document with this group");
|
||||
if (docObj->getDocumentObjectPtr()->getDocument()
|
||||
!= getGroupExtensionPtr()->getExtendedObject()->getDocument()) {
|
||||
PyErr_SetString(Base::PyExc_FC_GeneralError,
|
||||
"Cannot check an object from another document with this group");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -275,7 +309,7 @@ PyObject* GroupExtensionPy::hasObject(PyObject *args)
|
||||
return PyBool_FromLong(v ? 1 : 0);
|
||||
}
|
||||
|
||||
PyObject *GroupExtensionPy::getCustomAttributes(const char* /*attr*/) const
|
||||
PyObject* GroupExtensionPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -32,9 +32,9 @@ PROPERTY_SOURCE(Image::ImagePlane, App::GeoFeature)
|
||||
|
||||
ImagePlane::ImagePlane()
|
||||
{
|
||||
ADD_PROPERTY_TYPE( ImageFile,(nullptr) , "ImagePlane",App::Prop_None,"File of the image");
|
||||
ADD_PROPERTY_TYPE( XSize, (100), "ImagePlane",App::Prop_None,"Size of a pixel in X");
|
||||
ADD_PROPERTY_TYPE( YSize, (100), "ImagePlane",App::Prop_None,"Size of a pixel in Y");
|
||||
ADD_PROPERTY_TYPE(ImageFile, (nullptr), "ImagePlane", App::Prop_None, "File of the image");
|
||||
ADD_PROPERTY_TYPE(XSize, (100), "ImagePlane", App::Prop_None, "Size of a pixel in X");
|
||||
ADD_PROPERTY_TYPE(YSize, (100), "ImagePlane", App::Prop_None, "Size of a pixel in Y");
|
||||
}
|
||||
|
||||
int ImagePlane::getXSizeInPixel()
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
namespace Image
|
||||
{
|
||||
|
||||
class AppExport ImagePlane : public App::GeoFeature
|
||||
class AppExport ImagePlane: public App::GeoFeature
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(Image::ImagePlane);
|
||||
|
||||
@@ -40,24 +40,25 @@ public:
|
||||
~ImagePlane() override = default;
|
||||
|
||||
App::PropertyFileIncluded ImageFile;
|
||||
App::PropertyLength XSize;
|
||||
App::PropertyLength YSize;
|
||||
App::PropertyLength XSize;
|
||||
App::PropertyLength YSize;
|
||||
|
||||
int getXSizeInPixel();
|
||||
int getYSizeInPixel();
|
||||
void setXSizeInPixel(int);
|
||||
void setYSizeInPixel(int);
|
||||
|
||||
double XPixelsPerMeter{1000.0};
|
||||
double YPixelsPerMeter{1000.0};
|
||||
double XPixelsPerMeter {1000.0};
|
||||
double YPixelsPerMeter {1000.0};
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
const char* getViewProviderName() const override {
|
||||
const char* getViewProviderName() const override
|
||||
{
|
||||
return "Gui::ViewProviderImagePlane";
|
||||
}
|
||||
};
|
||||
|
||||
} //namespace Image
|
||||
} // namespace Image
|
||||
|
||||
|
||||
#endif // App_ImagePlane_H
|
||||
#endif // App_ImagePlane_H
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <cstdlib>
|
||||
# include <unordered_set>
|
||||
#include <cstdlib>
|
||||
#include <unordered_set>
|
||||
#endif
|
||||
|
||||
#include "IndexedName.h"
|
||||
@@ -37,17 +37,17 @@ using namespace Data;
|
||||
/// Check whether the input character is an underscore or an ASCII letter a-Z or A-Z
|
||||
inline bool isInvalidChar(char test)
|
||||
{
|
||||
return test != '_' && (test < 'a' || test > 'z' ) && (test < 'A' || test > 'Z');
|
||||
return test != '_' && (test < 'a' || test > 'z') && (test < 'A' || test > 'Z');
|
||||
}
|
||||
|
||||
/// Get the integer suffix of name. Returns a tuple of (suffix, suffixPosition). Calling code
|
||||
/// should check to ensure that suffixPosition is not equal to nameLength (in which case there was no
|
||||
/// suffix).
|
||||
/// should check to ensure that suffixPosition is not equal to nameLength (in which case there was
|
||||
/// no suffix).
|
||||
///
|
||||
/// \param name The name to check
|
||||
/// \param nameLength The length of the string in name
|
||||
/// \returns An integer pair of the suffix itself and the position of that suffix in name
|
||||
std::pair<int,int> getIntegerSuffix(const char *name, int nameLength)
|
||||
std::pair<int, int> getIntegerSuffix(const char* name, int nameLength)
|
||||
{
|
||||
int suffixPosition {nameLength - 1};
|
||||
|
||||
@@ -68,11 +68,10 @@ std::pair<int,int> getIntegerSuffix(const char *name, int nameLength)
|
||||
return std::make_pair(suffix, suffixPosition);
|
||||
}
|
||||
|
||||
void IndexedName::set(
|
||||
const char* name,
|
||||
int length,
|
||||
const std::vector<const char*>& allowedNames,
|
||||
bool allowOthers)
|
||||
void IndexedName::set(const char* name,
|
||||
int length,
|
||||
const std::vector<const char*>& allowedNames,
|
||||
bool allowOthers)
|
||||
{
|
||||
// Storage for names that we weren't given external storage for
|
||||
static std::unordered_set<ByteArray, ByteArrayHasher> NameSet;
|
||||
@@ -90,22 +89,22 @@ void IndexedName::set(
|
||||
// underscore. If any other character appears, reject the entire string.
|
||||
// When we support C++20 we can use std::span<> to eliminate the clang-tidy warning
|
||||
// NOLINTNEXTLINE cppcoreguidelines-pro-bounds-pointer-arithmetic
|
||||
if (std::any_of(name, name+suffixPosition, isInvalidChar)) {
|
||||
if (std::any_of(name, name + suffixPosition, isInvalidChar)) {
|
||||
this->type = "";
|
||||
return;
|
||||
}
|
||||
|
||||
// If a list of allowedNames was provided, see if our set name matches one of those allowedNames: if it
|
||||
// does, reference that memory location and return.
|
||||
for (const auto *typeName : allowedNames) {
|
||||
// If a list of allowedNames was provided, see if our set name matches one of those
|
||||
// allowedNames: if it does, reference that memory location and return.
|
||||
for (const auto* typeName : allowedNames) {
|
||||
if (std::strncmp(name, typeName, suffixPosition) == 0) {
|
||||
this->type = typeName;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the type was NOT in the list of allowedNames, but the caller has set the allowOthers flag to
|
||||
// true, then add the new type to the static NameSet (if it is not already there).
|
||||
// If the type was NOT in the list of allowedNames, but the caller has set the allowOthers flag
|
||||
// to true, then add the new type to the static NameSet (if it is not already there).
|
||||
if (allowOthers) {
|
||||
auto res = NameSet.insert(ByteArray(QByteArray::fromRawData(name, suffixPosition)));
|
||||
if (res.second /*The insert succeeded (the type was new)*/) {
|
||||
|
||||
@@ -40,21 +40,21 @@
|
||||
namespace Data
|
||||
{
|
||||
|
||||
/// The IndexedName class provides a very memory-efficient data structure to hold a name and an index
|
||||
/// value, and to perform various comparisons and validations of those values. The name must only
|
||||
/// consist of upper- and lower-case ASCII characters and the underscore ('_') character. The index
|
||||
/// must be a positive integer. The string representation of this IndexedName is the name followed by
|
||||
/// the index, with no spaces between: an IndexedName may be constructed from this string. For
|
||||
/// example "EDGE1" or "FACE345" might be the names of elements that use an IndexedName. If there is
|
||||
/// then an "EDGE2", only a pointer to the original stored name "EDGE" is retained.
|
||||
/// The IndexedName class provides a very memory-efficient data structure to hold a name and an
|
||||
/// index value, and to perform various comparisons and validations of those values. The name must
|
||||
/// only consist of upper- and lower-case ASCII characters and the underscore ('_') character. The
|
||||
/// index must be a positive integer. The string representation of this IndexedName is the name
|
||||
/// followed by the index, with no spaces between: an IndexedName may be constructed from this
|
||||
/// string. For example "EDGE1" or "FACE345" might be the names of elements that use an IndexedName.
|
||||
/// If there is then an "EDGE2", only a pointer to the original stored name "EDGE" is retained.
|
||||
///
|
||||
/// The memory efficiency of the class comes from re-using the same character storage for names that
|
||||
/// match, while retaining their differing indices. This is achieved by either using user-provided
|
||||
/// const char * names (provided as a list of typeNames and presumed to never be deallocated), or by
|
||||
/// maintaining an internal list of names that have been used before, and can be re-used later.
|
||||
class AppExport IndexedName {
|
||||
class AppExport IndexedName
|
||||
{
|
||||
public:
|
||||
|
||||
/// Construct from a name and an optional index. If the name contains an index it is read, but
|
||||
/// is used as the index *only* if _index parameter is unset. If the _index parameter is given
|
||||
/// it overrides any trailing integer in the name. Index must be positive, and name must contain
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
/// \param name The new name - ASCII letters and underscores only, with optional integer suffix.
|
||||
/// This memory will be copied into a new internal storage location and need not be persistent.
|
||||
/// \param _index The new index - if provided, it overrides any suffix provided by name
|
||||
explicit IndexedName(const char *name = nullptr, int _index = 0)
|
||||
explicit IndexedName(const char* name = nullptr, int _index = 0)
|
||||
: index(0)
|
||||
{
|
||||
assert(_index >= 0);
|
||||
@@ -93,9 +93,11 @@ public:
|
||||
/// \param allowOthers Whether a name not in allowedTypeNames is permitted. If true (the
|
||||
/// default) then a name not in allowedTypeNames is added to a static internal storage vector
|
||||
/// so that it can be re-used later without additional memory allocation.
|
||||
IndexedName(const char *name,
|
||||
const std::vector<const char*> & allowedTypeNames,
|
||||
bool allowOthers=true) : type(""), index(0)
|
||||
IndexedName(const char* name,
|
||||
const std::vector<const char*>& allowedTypeNames,
|
||||
bool allowOthers = true)
|
||||
: type("")
|
||||
, index(0)
|
||||
{
|
||||
set(name, -1, allowedTypeNames, allowOthers);
|
||||
}
|
||||
@@ -105,7 +107,9 @@ public:
|
||||
/// is made.
|
||||
///
|
||||
/// \param data The QByteArray to copy the data from
|
||||
explicit IndexedName(const QByteArray & data) : type(""), index(0)
|
||||
explicit IndexedName(const QByteArray& data)
|
||||
: type("")
|
||||
, index(0)
|
||||
{
|
||||
set(data.constData(), data.size());
|
||||
}
|
||||
@@ -117,8 +121,9 @@ public:
|
||||
/// \param name The name of the object. This memory is NOT copied and must be persistent.
|
||||
/// \param index A positive, non-zero integer
|
||||
/// \return An IndexedName with the given name and index, re-using the existing memory for name
|
||||
static IndexedName fromConst(const char *name, int index) {
|
||||
assert (index >= 0);
|
||||
static IndexedName fromConst(const char* name, int index)
|
||||
{
|
||||
assert(index >= 0);
|
||||
IndexedName res;
|
||||
res.type = name;
|
||||
res.index = index;
|
||||
@@ -130,7 +135,7 @@ public:
|
||||
///
|
||||
/// \param buffer A (possibly non-empty) string buffer to append the name to.
|
||||
/// \return A const char pointer to the name we appended to the buffer.
|
||||
const char * appendToStringBuffer(std::string & buffer) const
|
||||
const char* appendToStringBuffer(std::string& buffer) const
|
||||
{
|
||||
// Note! buffer is not cleared on purpose.
|
||||
std::size_t offset = buffer.size();
|
||||
@@ -153,7 +158,7 @@ public:
|
||||
|
||||
/// An indexedName is represented as the simple concatenation of the name and its index, e.g.
|
||||
/// "EDGE1" or "FACE42".
|
||||
friend std::ostream & operator<<(std::ostream & stream, const IndexedName & indexedName)
|
||||
friend std::ostream& operator<<(std::ostream& stream, const IndexedName& indexedName)
|
||||
{
|
||||
stream << indexedName.type;
|
||||
if (indexedName.index > 0) {
|
||||
@@ -163,15 +168,14 @@ public:
|
||||
}
|
||||
|
||||
/// True only if both the name and index compare exactly equal.
|
||||
bool operator==(const IndexedName & other) const
|
||||
bool operator==(const IndexedName& other) const
|
||||
{
|
||||
return this->index == other.index
|
||||
&& (this->type == other.type
|
||||
|| std::strcmp(this->type, other.type)==0);
|
||||
&& (this->type == other.type || std::strcmp(this->type, other.type) == 0);
|
||||
}
|
||||
|
||||
/// Increments the index by the given offset. Does not affect the text part of the name.
|
||||
IndexedName & operator+=(int offset)
|
||||
IndexedName& operator+=(int offset)
|
||||
{
|
||||
this->index += offset;
|
||||
assert(this->index >= 0);
|
||||
@@ -179,7 +183,7 @@ public:
|
||||
}
|
||||
|
||||
/// Pre-increment operator: increases the index of this element by one.
|
||||
IndexedName & operator++()
|
||||
IndexedName& operator++()
|
||||
{
|
||||
++this->index;
|
||||
return *this;
|
||||
@@ -187,7 +191,7 @@ public:
|
||||
|
||||
/// Pre-decrement operator: decreases the index of this element by one. Must not make the index
|
||||
/// negative (only checked when compiled in debug mode).
|
||||
IndexedName & operator--()
|
||||
IndexedName& operator--()
|
||||
{
|
||||
--this->index;
|
||||
assert(this->index >= 0);
|
||||
@@ -195,13 +199,13 @@ public:
|
||||
}
|
||||
|
||||
/// True if either the name or the index compare not equal.
|
||||
bool operator!=(const IndexedName & other) const
|
||||
bool operator!=(const IndexedName& other) const
|
||||
{
|
||||
return !(this->operator==(other));
|
||||
}
|
||||
|
||||
/// Equivalent to C++20's operator <=>
|
||||
int compare(const IndexedName & other) const
|
||||
int compare(const IndexedName& other) const
|
||||
{
|
||||
int res = std::strcmp(this->type, other.type);
|
||||
if (res != 0) {
|
||||
@@ -218,7 +222,7 @@ public:
|
||||
|
||||
/// Provided to enable sorting operations: the comparison is first lexicographical for the text
|
||||
/// element of the names, then numerical for the indices.
|
||||
bool operator<(const IndexedName & other) const
|
||||
bool operator<(const IndexedName& other) const
|
||||
{
|
||||
return compare(other) < 0;
|
||||
}
|
||||
@@ -235,25 +239,41 @@ public:
|
||||
}
|
||||
|
||||
/// Get a pointer to text part of the name - does NOT make a copy, returns direct memory access
|
||||
const char * getType() const { return this->type; }
|
||||
const char* getType() const
|
||||
{
|
||||
return this->type;
|
||||
}
|
||||
|
||||
/// Get the numerical part of the name
|
||||
int getIndex() const { return this->index; }
|
||||
int getIndex() const
|
||||
{
|
||||
return this->index;
|
||||
}
|
||||
|
||||
/// Set the numerical part of the name (note that there is no equivalent function to allow
|
||||
/// changing the text part of the name, which is immutable once created).
|
||||
///
|
||||
/// \param input The new index. Must be a positive non-zero integer
|
||||
void setIndex(int input) { assert(input>=0); this->index = input; }
|
||||
void setIndex(int input)
|
||||
{
|
||||
assert(input >= 0);
|
||||
this->index = input;
|
||||
}
|
||||
|
||||
/// A name is considered "null" if its text component is an empty string.
|
||||
// When we support C++20 we can use std::span<> to eliminate the clang-tidy warning
|
||||
// NOLINTNEXTLINE cppcoreguidelines-pro-bounds-pointer-arithmetic
|
||||
bool isNull() const { return this->type[0] == '\0'; }
|
||||
bool isNull() const
|
||||
{
|
||||
return this->type[0] == '\0';
|
||||
}
|
||||
|
||||
/// Boolean conversion provides the opposite of isNull(), yielding true when the text part of
|
||||
/// the name is NOT the empty string.
|
||||
explicit operator bool() const { return !isNull(); }
|
||||
explicit operator bool() const
|
||||
{
|
||||
return !isNull();
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Apply the IndexedName rules and either store the characters of a new type or a reference to
|
||||
@@ -268,13 +288,13 @@ protected:
|
||||
/// \param allowOthers If true (the default), then if name is not in allowedNames it is allowed,
|
||||
/// and it is added to internal storage (making a copy of the name if this is its first
|
||||
/// occurrence).
|
||||
void set(const char *name,
|
||||
void set(const char* name,
|
||||
int length = -1,
|
||||
const std::vector<const char *> & allowedNames = {},
|
||||
const std::vector<const char*>& allowedNames = {},
|
||||
bool allowOthers = true);
|
||||
|
||||
private:
|
||||
const char * type;
|
||||
const char* type;
|
||||
int index;
|
||||
};
|
||||
|
||||
@@ -285,13 +305,13 @@ private:
|
||||
struct ByteArray
|
||||
{
|
||||
explicit ByteArray(QByteArray other)
|
||||
:bytes(std::move(other))
|
||||
: bytes(std::move(other))
|
||||
{}
|
||||
|
||||
ByteArray(const ByteArray& other) = default;
|
||||
|
||||
ByteArray(ByteArray&& other) noexcept
|
||||
:bytes(std::move(other.bytes))
|
||||
: bytes(std::move(other.bytes))
|
||||
{}
|
||||
|
||||
~ByteArray() = default;
|
||||
@@ -304,17 +324,19 @@ struct ByteArray
|
||||
bytes = copy;
|
||||
}
|
||||
|
||||
bool operator==(const ByteArray& other) const {
|
||||
bool operator==(const ByteArray& other) const
|
||||
{
|
||||
return bytes == other.bytes;
|
||||
}
|
||||
|
||||
ByteArray &operator=(const ByteArray & other) {
|
||||
ByteArray& operator=(const ByteArray& other)
|
||||
{
|
||||
bytes.clear();
|
||||
bytes.append(other.bytes.constData(), other.bytes.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
ByteArray &operator= (ByteArray&& other) noexcept
|
||||
ByteArray& operator=(ByteArray&& other) noexcept
|
||||
{
|
||||
bytes = std::move(other.bytes);
|
||||
return *this;
|
||||
@@ -337,6 +359,6 @@ struct ByteArrayHasher
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Data
|
||||
|
||||
#endif // APP_INDEXEDNAME_H
|
||||
#endif // APP_INDEXEDNAME_H
|
||||
|
||||
@@ -32,10 +32,10 @@ using namespace App;
|
||||
PROPERTY_SOURCE(App::InventorObject, App::GeoFeature)
|
||||
|
||||
|
||||
InventorObject::InventorObject()
|
||||
InventorObject::InventorObject()
|
||||
{
|
||||
ADD_PROPERTY_TYPE(Buffer,(""),"",Prop_None,"String buffer with a scene graph");
|
||||
ADD_PROPERTY_TYPE(FileName,(""),"",Prop_None,"Path to an Inventor file");
|
||||
ADD_PROPERTY_TYPE(Buffer, (""), "", Prop_None, "String buffer with a scene graph");
|
||||
ADD_PROPERTY_TYPE(FileName, (""), "", Prop_None, "Path to an Inventor file");
|
||||
}
|
||||
|
||||
InventorObject::~InventorObject() = default;
|
||||
@@ -45,11 +45,11 @@ short InventorObject::mustExecute() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject *InventorObject::getPyObject()
|
||||
PyObject* InventorObject::getPyObject()
|
||||
{
|
||||
if (PythonObject.is(Py::_None())){
|
||||
if (PythonObject.is(Py::_None())) {
|
||||
// ref counter is set to 1
|
||||
PythonObject = Py::Object(new DocumentObjectPy(this),true);
|
||||
PythonObject = Py::Object(new DocumentObjectPy(this), true);
|
||||
}
|
||||
return Py::new_reference_to(PythonObject);
|
||||
return Py::new_reference_to(PythonObject);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
namespace App
|
||||
{
|
||||
|
||||
class AppExport InventorObject : public GeoFeature
|
||||
class AppExport InventorObject: public GeoFeature
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(App::InventorObject);
|
||||
|
||||
@@ -41,20 +41,22 @@ public:
|
||||
~InventorObject() override;
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
const char* getViewProviderName() const override {
|
||||
const char* getViewProviderName() const override
|
||||
{
|
||||
return "Gui::ViewProviderInventorObject";
|
||||
}
|
||||
DocumentObjectExecReturn *execute() override {
|
||||
DocumentObjectExecReturn* execute() override
|
||||
{
|
||||
return DocumentObject::StdReturn;
|
||||
}
|
||||
short mustExecute() const override;
|
||||
PyObject *getPyObject() override;
|
||||
PyObject* getPyObject() override;
|
||||
|
||||
PropertyString Buffer;
|
||||
PropertyString FileName;
|
||||
};
|
||||
|
||||
} //namespace App
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // APP_INVENTOROBJECT_H
|
||||
#endif // APP_INVENTOROBJECT_H
|
||||
|
||||
@@ -75,6 +75,6 @@ int constexpr findLicense(const char* identifier)
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}// namespace App
|
||||
} // namespace App
|
||||
|
||||
#endif// APP_LICENSE_H
|
||||
#endif // APP_LICENSE_H
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <cstdlib>
|
||||
# include <unordered_set>
|
||||
#include <cstdlib>
|
||||
#include <unordered_set>
|
||||
#endif
|
||||
|
||||
#include "DocumentObject.h"
|
||||
@@ -164,9 +164,12 @@ bool ElementNameComparator::operator()(const MappedName& leftName,
|
||||
return leftName.size() < rightName.size();
|
||||
}
|
||||
|
||||
HistoryItem::HistoryItem(App::DocumentObject *obj, const Data::MappedName &name)
|
||||
:obj(obj),tag(0),element(name)
|
||||
HistoryItem::HistoryItem(App::DocumentObject* obj, const Data::MappedName& name)
|
||||
: obj(obj)
|
||||
, tag(0)
|
||||
, element(name)
|
||||
{
|
||||
if(obj)
|
||||
if (obj) {
|
||||
tag = obj->getID();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,13 +46,13 @@ struct AppExport MappedElement
|
||||
MappedElement() = default;
|
||||
|
||||
MappedElement(const IndexedName& idx, MappedName n)
|
||||
: index(idx),
|
||||
name(std::move(n))
|
||||
: index(idx)
|
||||
, name(std::move(n))
|
||||
{}
|
||||
|
||||
MappedElement(MappedName n, const IndexedName& idx)
|
||||
: index(idx),
|
||||
name(std::move(n))
|
||||
: index(idx)
|
||||
, name(std::move(n))
|
||||
{}
|
||||
|
||||
~MappedElement() = default;
|
||||
@@ -60,8 +60,8 @@ struct AppExport MappedElement
|
||||
MappedElement(const MappedElement& other) = default;
|
||||
|
||||
MappedElement(MappedElement&& other) noexcept
|
||||
: index(other.index),
|
||||
name(std::move(other.name))
|
||||
: index(other.index)
|
||||
, name(std::move(other.name))
|
||||
{}
|
||||
|
||||
MappedElement& operator=(MappedElement&& other) noexcept
|
||||
@@ -99,16 +99,18 @@ struct AppExport MappedElement
|
||||
}
|
||||
};
|
||||
|
||||
struct AppExport HistoryItem {
|
||||
App::DocumentObject *obj;
|
||||
struct AppExport HistoryItem
|
||||
{
|
||||
App::DocumentObject* obj;
|
||||
long tag;
|
||||
Data::MappedName element;
|
||||
Data::IndexedName index;
|
||||
std::vector<Data::MappedName> intermediates;
|
||||
HistoryItem(App::DocumentObject *obj, const Data::MappedName &name);
|
||||
HistoryItem(App::DocumentObject* obj, const Data::MappedName& name);
|
||||
};
|
||||
|
||||
struct AppExport ElementNameComparator {
|
||||
struct AppExport ElementNameComparator
|
||||
{
|
||||
/** Comparison function to make topo name more stable
|
||||
*
|
||||
* The sorting decomposes the name into either of the following two forms
|
||||
@@ -121,10 +123,10 @@ struct AppExport ElementNameComparator {
|
||||
* The reason for this is to prevent names with bigger digits (which usually means
|
||||
* they come later in history) from coming earlier when sorting.
|
||||
*/
|
||||
bool operator()(const MappedName & leftName, const MappedName & rightName) const;
|
||||
bool operator()(const MappedName& leftName, const MappedName& rightName) const;
|
||||
};
|
||||
|
||||
}// namespace Data
|
||||
} // namespace Data
|
||||
|
||||
|
||||
#endif// APP_MAPPED_ELEMENT_H
|
||||
#endif // APP_MAPPED_ELEMENT_H
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <unordered_set>
|
||||
#include <unordered_set>
|
||||
#endif
|
||||
|
||||
#include "MappedName.h"
|
||||
@@ -34,13 +34,15 @@
|
||||
#include <boost/iostreams/stream.hpp>
|
||||
|
||||
|
||||
FC_LOG_LEVEL_INIT("MappedName", true, 2);// NOLINT
|
||||
FC_LOG_LEVEL_INIT("MappedName", true, 2); // NOLINT
|
||||
|
||||
namespace Data {
|
||||
namespace Data
|
||||
{
|
||||
|
||||
void MappedName::compact() const
|
||||
{
|
||||
auto self = const_cast<MappedName*>(this); //FIXME this is a workaround for a single call in ElementMap::addName()
|
||||
auto self = const_cast<MappedName*>(
|
||||
this); // FIXME this is a workaround for a single call in ElementMap::addName()
|
||||
|
||||
if (this->raw) {
|
||||
self->data = QByteArray(self->data.constData(), self->data.size());
|
||||
@@ -49,8 +51,12 @@ void MappedName::compact() const
|
||||
}
|
||||
|
||||
|
||||
int MappedName::findTagInElementName(long* tagOut, int* lenOut, std::string* postfixOut,
|
||||
char* typeOut, bool negative, bool recursive) const
|
||||
int MappedName::findTagInElementName(long* tagOut,
|
||||
int* lenOut,
|
||||
std::string* postfixOut,
|
||||
char* typeOut,
|
||||
bool negative,
|
||||
bool recursive) const
|
||||
{
|
||||
bool hex = true;
|
||||
int pos = this->rfind(POSTFIX_TAG);
|
||||
@@ -61,7 +67,7 @@ int MappedName::findTagInElementName(long* tagOut, int* lenOut, std::string* pos
|
||||
// |
|
||||
// pos
|
||||
|
||||
if(pos < 0) {
|
||||
if (pos < 0) {
|
||||
pos = this->rfind(POSTFIX_DECIMAL_TAG);
|
||||
if (pos < 0) {
|
||||
return -1;
|
||||
@@ -77,7 +83,7 @@ int MappedName::findTagInElementName(long* tagOut, int* lenOut, std::string* pos
|
||||
char eof = 0;
|
||||
|
||||
int size {0};
|
||||
const char * nameAsChars = this->toConstString(offset, size);
|
||||
const char* nameAsChars = this->toConstString(offset, size);
|
||||
|
||||
// check if the number followed by the tagPosfix is negative
|
||||
bool isNegative = (nameAsChars[0] == '-');
|
||||
@@ -89,7 +95,8 @@ int MappedName::findTagInElementName(long* tagOut, int* lenOut, std::string* pos
|
||||
if (!hex) {
|
||||
// no hex is an older version of the encoding scheme
|
||||
iss >> _tag >> sep;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// The purpose of tagOut postfixOut is to encode one model operation. The
|
||||
// 'tagOut' field is used to record the own object ID of that model shape,
|
||||
// and the 'lenOut' field indicates the length of the operation codes
|
||||
@@ -148,13 +155,13 @@ int MappedName::findTagInElementName(long* tagOut, int* lenOut, std::string* pos
|
||||
}
|
||||
|
||||
if (hex) {
|
||||
if (pos-_len < 0) {
|
||||
if (pos - _len < 0) {
|
||||
return -1;
|
||||
}
|
||||
if ((_len != 0) && recursive && (tagOut || lenOut)) {
|
||||
// in case of recursive tagOut postfixOut (used by hierarchy element
|
||||
// map), look for any embedded tagOut postfixOut
|
||||
int next = MappedName::fromRawData(*this, pos-_len, _len).rfind(POSTFIX_TAG);
|
||||
int next = MappedName::fromRawData(*this, pos - _len, _len).rfind(POSTFIX_TAG);
|
||||
if (next >= 0) {
|
||||
next += pos - _len;
|
||||
// #94;:G0;XTR;:H19:8,F;:H1a,F;BND:-1:0;:H1b:10,F
|
||||
@@ -174,7 +181,7 @@ int MappedName::findTagInElementName(long* tagOut, int* lenOut, std::string* pos
|
||||
.find(ELEMENT_MAP_PREFIX);
|
||||
}
|
||||
if (end >= 0) {
|
||||
end += next+1;
|
||||
end += next + 1;
|
||||
// #94;:G0;XTR;:H19:8,F;:H1a,F;BND:-1:0;:H1b:10,F
|
||||
// ^
|
||||
// |
|
||||
@@ -183,7 +190,8 @@ int MappedName::findTagInElementName(long* tagOut, int* lenOut, std::string* pos
|
||||
// #94;:G0;XTR;:H19:8,F;:H1a,F;BND:-1:0;:H1b:10,F
|
||||
// | |
|
||||
// -- lenOut --
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
_len = 0;
|
||||
}
|
||||
}
|
||||
@@ -196,28 +204,28 @@ int MappedName::findTagInElementName(long* tagOut, int* lenOut, std::string* pos
|
||||
// ----------- lenOut -----------
|
||||
_len = pos - _len;
|
||||
}
|
||||
if(typeOut) {
|
||||
if (typeOut) {
|
||||
*typeOut = tp;
|
||||
}
|
||||
if(tagOut) {
|
||||
if (tagOut) {
|
||||
if (_tag == 0 && recursive) {
|
||||
return MappedName(*this, 0, _len)
|
||||
.findTagInElementName(tagOut, lenOut, postfixOut, typeOut, negative);
|
||||
}
|
||||
if(_tag>0 || negative) {
|
||||
if (_tag > 0 || negative) {
|
||||
*tagOut = _tag;
|
||||
}
|
||||
else {
|
||||
*tagOut = -_tag;
|
||||
}
|
||||
}
|
||||
if(lenOut) {
|
||||
if (lenOut) {
|
||||
*lenOut = _len;
|
||||
}
|
||||
if(postfixOut) {
|
||||
if (postfixOut) {
|
||||
*postfixOut = this->toString(pos);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Data
|
||||
|
||||
@@ -415,7 +415,7 @@ public:
|
||||
}
|
||||
|
||||
|
||||
if (startPosition < other.data.size())// if starting inside data
|
||||
if (startPosition < other.data.size()) // if starting inside data
|
||||
{
|
||||
int count = size;
|
||||
// make sure count doesn't exceed data size and end up in postfix
|
||||
@@ -436,7 +436,7 @@ public:
|
||||
startPosition = 0;
|
||||
size -= count;
|
||||
}
|
||||
else// else starting inside postfix
|
||||
else // else starting inside postfix
|
||||
{
|
||||
startPosition -= other.data.size();
|
||||
}
|
||||
@@ -879,7 +879,8 @@ public:
|
||||
return false;
|
||||
}
|
||||
return startsWith(
|
||||
QByteArray::fromRawData(searchTarget, static_cast<int>(qstrlen(searchTarget))), offset);
|
||||
QByteArray::fromRawData(searchTarget, static_cast<int>(qstrlen(searchTarget))),
|
||||
offset);
|
||||
}
|
||||
|
||||
/// Returns true if this MappedName starts with the search target. If there is a postfix, only
|
||||
@@ -902,15 +903,18 @@ public:
|
||||
/// \param lenOut: optional pointer to receive the length field after the tagOut field.
|
||||
/// This gives the length of the previous hashed element name starting
|
||||
/// from the beginning of the give element name.
|
||||
/// \param postfixOut: optional pointer to receive the postfixOut starting at the found tagOut field.
|
||||
/// \param typeOut: optional pointer to receive the element typeOut character
|
||||
/// \param negative: return negative tagOut as it is. If disabled, then always return positive tagOut.
|
||||
/// \param postfixOut: optional pointer to receive the postfixOut starting at the found tagOut
|
||||
/// field. \param typeOut: optional pointer to receive the element typeOut character \param
|
||||
/// negative: return negative tagOut as it is. If disabled, then always return positive tagOut.
|
||||
/// Negative tagOut is sometimes used for element disambiguation.
|
||||
/// \param recursive: recursively find the last non-zero tagOut
|
||||
///
|
||||
/// \return Return the end position of the tagOut field, or return -1 if not found.
|
||||
int findTagInElementName(long* tagOut = nullptr, int* lenOut = nullptr, std::string* postfixOut = nullptr,
|
||||
char* typeOut = nullptr, bool negative = false,
|
||||
int findTagInElementName(long* tagOut = nullptr,
|
||||
int* lenOut = nullptr,
|
||||
std::string* postfixOut = nullptr,
|
||||
char* typeOut = nullptr,
|
||||
bool negative = false,
|
||||
bool recursive = true) const;
|
||||
|
||||
/// Get a hash for this MappedName
|
||||
@@ -1043,7 +1047,7 @@ struct MappedNameRef
|
||||
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
|
||||
|
||||
}// namespace Data
|
||||
} // namespace Data
|
||||
|
||||
|
||||
#endif// APP_MAPPED_NAME_H
|
||||
#endif // APP_MAPPED_NAME_H
|
||||
|
||||
@@ -33,20 +33,22 @@ PROPERTY_SOURCE(App::MaterialObject, App::DocumentObject)
|
||||
|
||||
MaterialObject::MaterialObject()
|
||||
{
|
||||
ADD_PROPERTY_TYPE(Material,(),"Material",Prop_None,"Material key/value map");
|
||||
|
||||
ADD_PROPERTY_TYPE(Material, (), "Material", Prop_None, "Material key/value map");
|
||||
}
|
||||
|
||||
// Python feature ---------------------------------------------------------
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
/// @cond DOXERR
|
||||
PROPERTY_SOURCE_TEMPLATE(App::MaterialObjectPython, App::MaterialObject)
|
||||
template<> const char* App::MaterialObjectPython::getViewProviderName() const {
|
||||
template<>
|
||||
const char* App::MaterialObjectPython::getViewProviderName() const
|
||||
{
|
||||
return "Gui::ViewProviderMaterialObjectPython";
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
// explicit template instantiation
|
||||
template class AppExport FeaturePythonT<App::MaterialObject>;
|
||||
}
|
||||
} // namespace App
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
namespace App
|
||||
{
|
||||
|
||||
class AppExport MaterialObject : public DocumentObject
|
||||
class AppExport MaterialObject: public DocumentObject
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(App::MaterialObject);
|
||||
|
||||
@@ -43,16 +43,16 @@ public:
|
||||
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
const char* getViewProviderName() const override {
|
||||
const char* getViewProviderName() const override
|
||||
{
|
||||
return "Gui::ViewProviderMaterialObject";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
using MaterialObjectPython = App::FeaturePythonT<MaterialObject>;
|
||||
|
||||
|
||||
} //namespace App
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // APP_MaterialObject_H
|
||||
#endif // APP_MaterialObject_H
|
||||
|
||||
@@ -28,179 +28,208 @@
|
||||
|
||||
#include "MeasureManager.h"
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
|
||||
std::vector<MeasureHandler> MeasureManager::_mMeasureHandlers;
|
||||
std::vector<MeasureType*> MeasureManager::_mMeasureTypes;
|
||||
std::vector<MeasureHandler> MeasureManager::_mMeasureHandlers;
|
||||
std::vector<MeasureType*> MeasureManager::_mMeasureTypes;
|
||||
|
||||
MeasureManager::MeasureManager()
|
||||
{
|
||||
// Constructor implementation
|
||||
MeasureManager::MeasureManager()
|
||||
{
|
||||
// Constructor implementation
|
||||
}
|
||||
|
||||
|
||||
void MeasureManager::addMeasureHandler(const char* module, MeasureTypeMethod typeCb)
|
||||
{
|
||||
_mMeasureHandlers.emplace_back(MeasureHandler {module, typeCb});
|
||||
}
|
||||
|
||||
bool MeasureManager::hasMeasureHandler(const char* module)
|
||||
{
|
||||
for (MeasureHandler& handler : _mMeasureHandlers) {
|
||||
if (strcmp(handler.module.c_str(), module) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MeasureHandler MeasureManager::getMeasureHandler(const char* module)
|
||||
{
|
||||
for (MeasureHandler handler : _mMeasureHandlers) {
|
||||
if (!strcmp(handler.module.c_str(), module)) {
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
|
||||
MeasureHandler empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
void MeasureManager::addMeasureHandler(const char* module, MeasureTypeMethod typeCb) {
|
||||
_mMeasureHandlers.emplace_back(MeasureHandler{module, typeCb});
|
||||
MeasureHandler MeasureManager::getMeasureHandler(const App::MeasureSelectionItem& selectionItem)
|
||||
{
|
||||
auto objT = selectionItem.object;
|
||||
|
||||
// Resolve App::Link
|
||||
App::DocumentObject* sub = objT.getSubObject();
|
||||
if (sub->isDerivedFrom<App::Link>()) {
|
||||
auto link = static_cast<App::Link*>(sub);
|
||||
sub = link->getLinkedObject(true);
|
||||
}
|
||||
|
||||
bool MeasureManager::hasMeasureHandler(const char* module) {
|
||||
for(MeasureHandler& handler : _mMeasureHandlers) {
|
||||
if (strcmp(handler.module.c_str(), module) == 0) {
|
||||
return true;
|
||||
const char* className = sub->getTypeId().getName();
|
||||
std::string mod = Base::Type::getModuleName(className);
|
||||
|
||||
return getMeasureHandler(mod.c_str());
|
||||
}
|
||||
|
||||
MeasureElementType
|
||||
MeasureManager::getMeasureElementType(const App::MeasureSelectionItem& selectionItem)
|
||||
{
|
||||
auto handler = getMeasureHandler(selectionItem);
|
||||
if (handler.module.empty()) {
|
||||
return App::MeasureElementType::INVALID;
|
||||
}
|
||||
|
||||
auto objT = selectionItem.object;
|
||||
return handler.typeCb(objT.getObject(), objT.getSubName().c_str());
|
||||
}
|
||||
|
||||
void MeasureManager::addMeasureType(MeasureType* measureType)
|
||||
{
|
||||
_mMeasureTypes.push_back(measureType);
|
||||
}
|
||||
|
||||
void MeasureManager::addMeasureType(std::string id,
|
||||
std::string label,
|
||||
std::string measureObj,
|
||||
MeasureValidateMethod validatorCb,
|
||||
MeasurePrioritizeMethod prioritizeCb)
|
||||
{
|
||||
MeasureType* mType =
|
||||
new MeasureType {id, label, measureObj, validatorCb, prioritizeCb, false, nullptr};
|
||||
_mMeasureTypes.push_back(mType);
|
||||
}
|
||||
|
||||
void MeasureManager::addMeasureType(const char* id,
|
||||
const char* label,
|
||||
const char* measureObj,
|
||||
MeasureValidateMethod validatorCb,
|
||||
MeasurePrioritizeMethod prioritizeCb)
|
||||
{
|
||||
addMeasureType(std::string(id),
|
||||
std::string(label),
|
||||
std::string(measureObj),
|
||||
validatorCb,
|
||||
prioritizeCb);
|
||||
}
|
||||
|
||||
const std::vector<MeasureType*> MeasureManager::getMeasureTypes()
|
||||
{
|
||||
return _mMeasureTypes;
|
||||
}
|
||||
|
||||
|
||||
Py::Tuple MeasureManager::getSelectionPy(const App::MeasureSelection& selection)
|
||||
{
|
||||
// Convert selection to python list
|
||||
Py::Tuple selectionPy(selection.size());
|
||||
|
||||
int i = 0;
|
||||
for (auto it : selection) {
|
||||
|
||||
Py::Dict sel;
|
||||
sel.setItem("object", Py::asObject(it.object.getObject()->getPyObject()));
|
||||
sel.setItem("subName", Py::String(it.object.getSubName()));
|
||||
sel.setItem("pickedPoint", Py::asObject(new Base::VectorPy(it.pickedPoint)));
|
||||
|
||||
selectionPy.setItem(i, sel);
|
||||
|
||||
i++;
|
||||
}
|
||||
return selectionPy;
|
||||
}
|
||||
|
||||
|
||||
std::vector<MeasureType*> MeasureManager::getValidMeasureTypes(App::MeasureSelection selection,
|
||||
std::string mode)
|
||||
{
|
||||
Base::PyGILStateLocker lock;
|
||||
|
||||
// Convert selection to python list
|
||||
Py::Tuple selectionPy = getSelectionPy(selection);
|
||||
|
||||
// Store valid measure types
|
||||
std::vector<MeasureType*> validTypes;
|
||||
std::pair<int, MeasureType>();
|
||||
|
||||
|
||||
// Loop through measure types and check if they work with given selection
|
||||
for (App::MeasureType* mType : getMeasureTypes()) {
|
||||
|
||||
if (mode != "" && mType->label != mode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (mType->isPython) {
|
||||
// Parse Python measure types
|
||||
auto measurePyClass = Py::Object(mType->pythonClass);
|
||||
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, selectionPy);
|
||||
|
||||
Py::Object isValid;
|
||||
try {
|
||||
isValid = measurePyClass.callMemberFunction(std::string("isValidSelection"), args);
|
||||
}
|
||||
catch (const Py::Exception&) {
|
||||
Base::PyException e;
|
||||
e.ReportException();
|
||||
isValid = Py::False();
|
||||
}
|
||||
|
||||
if (isValid.as_bool()) {
|
||||
|
||||
// Check priority
|
||||
Py::Object isPriority;
|
||||
try {
|
||||
isPriority = measurePyClass.callMemberFunction("isPrioritySelection", args);
|
||||
}
|
||||
catch (const Py::Exception&) {
|
||||
Base::PyException e;
|
||||
e.ReportException();
|
||||
isPriority = Py::False();
|
||||
}
|
||||
|
||||
if (isPriority.as_bool()) {
|
||||
validTypes.insert(validTypes.begin(), mType);
|
||||
}
|
||||
else {
|
||||
validTypes.push_back(mType);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// Parse c++ measure types
|
||||
|
||||
MeasureHandler MeasureManager::getMeasureHandler(const char* module) {
|
||||
for(MeasureHandler handler : _mMeasureHandlers) {
|
||||
if (!strcmp(handler.module.c_str(), module)) {
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
|
||||
MeasureHandler empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
MeasureHandler MeasureManager::getMeasureHandler(const App::MeasureSelectionItem& selectionItem) {
|
||||
auto objT = selectionItem.object;
|
||||
|
||||
// Resolve App::Link
|
||||
App::DocumentObject* sub = objT.getSubObject();
|
||||
if (sub->isDerivedFrom<App::Link>()) {
|
||||
auto link = static_cast<App::Link*>(sub);
|
||||
sub = link->getLinkedObject(true);
|
||||
}
|
||||
|
||||
const char* className = sub->getTypeId().getName();
|
||||
std::string mod = Base::Type::getModuleName(className);
|
||||
|
||||
return getMeasureHandler(mod.c_str());
|
||||
}
|
||||
|
||||
MeasureElementType MeasureManager::getMeasureElementType(const App::MeasureSelectionItem& selectionItem) {
|
||||
auto handler = getMeasureHandler(selectionItem);
|
||||
if (handler.module.empty()) {
|
||||
return App::MeasureElementType::INVALID;
|
||||
}
|
||||
|
||||
auto objT = selectionItem.object;
|
||||
return handler.typeCb(objT.getObject(), objT.getSubName().c_str());
|
||||
}
|
||||
|
||||
void MeasureManager::addMeasureType(MeasureType* measureType) {
|
||||
_mMeasureTypes.push_back(measureType);
|
||||
}
|
||||
|
||||
void MeasureManager::addMeasureType(std::string id, std::string label, std::string measureObj, MeasureValidateMethod validatorCb, MeasurePrioritizeMethod prioritizeCb) {
|
||||
MeasureType* mType = new MeasureType{id, label, measureObj, validatorCb, prioritizeCb, false, nullptr};
|
||||
_mMeasureTypes.push_back(mType);
|
||||
}
|
||||
|
||||
void MeasureManager::addMeasureType(const char* id, const char* label, const char* measureObj, MeasureValidateMethod validatorCb, MeasurePrioritizeMethod prioritizeCb) {
|
||||
addMeasureType(std::string(id), std::string(label), std::string(measureObj), validatorCb, prioritizeCb);
|
||||
}
|
||||
|
||||
const std::vector<MeasureType*> MeasureManager::getMeasureTypes() {
|
||||
return _mMeasureTypes;
|
||||
}
|
||||
|
||||
|
||||
Py::Tuple MeasureManager::getSelectionPy(const App::MeasureSelection& selection) {
|
||||
// Convert selection to python list
|
||||
Py::Tuple selectionPy(selection.size());
|
||||
|
||||
int i = 0;
|
||||
for (auto it : selection) {
|
||||
|
||||
Py::Dict sel;
|
||||
sel.setItem("object", Py::asObject(it.object.getObject()->getPyObject()));
|
||||
sel.setItem("subName", Py::String(it.object.getSubName()));
|
||||
sel.setItem("pickedPoint", Py::asObject(new Base::VectorPy(it.pickedPoint)));
|
||||
|
||||
selectionPy.setItem(i, sel);
|
||||
|
||||
i++;
|
||||
}
|
||||
return selectionPy;
|
||||
}
|
||||
|
||||
|
||||
std::vector<MeasureType*> MeasureManager::getValidMeasureTypes(App::MeasureSelection selection, std::string mode) {
|
||||
Base::PyGILStateLocker lock;
|
||||
|
||||
// Convert selection to python list
|
||||
Py::Tuple selectionPy = getSelectionPy(selection);
|
||||
|
||||
// Store valid measure types
|
||||
std::vector<MeasureType*> validTypes;
|
||||
std::pair<int, MeasureType>();
|
||||
|
||||
|
||||
// Loop through measure types and check if they work with given selection
|
||||
for (App::MeasureType* mType : getMeasureTypes()){
|
||||
|
||||
if (mode != "" && mType->label != mode) {
|
||||
if (mType->validatorCb && !mType->validatorCb(selection)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (mType->isPython) {
|
||||
// Parse Python measure types
|
||||
auto measurePyClass = Py::Object(mType->pythonClass);
|
||||
|
||||
Py::Tuple args(1);
|
||||
args.setItem(0, selectionPy);
|
||||
|
||||
Py::Object isValid;
|
||||
try {
|
||||
isValid = measurePyClass.callMemberFunction(std::string("isValidSelection"), args);
|
||||
} catch (const Py::Exception&) {
|
||||
Base::PyException e;
|
||||
e.ReportException();
|
||||
isValid = Py::False();
|
||||
}
|
||||
|
||||
if (isValid.as_bool()) {
|
||||
|
||||
// Check priority
|
||||
Py::Object isPriority;
|
||||
try {
|
||||
isPriority = measurePyClass.callMemberFunction("isPrioritySelection", args);
|
||||
} catch (const Py::Exception&) {
|
||||
Base::PyException e;
|
||||
e.ReportException();
|
||||
isPriority = Py::False();
|
||||
}
|
||||
|
||||
if (isPriority.as_bool()) {
|
||||
validTypes.insert(validTypes.begin(), mType);
|
||||
} else {
|
||||
validTypes.push_back(mType);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Parse c++ measure types
|
||||
|
||||
if (mType->validatorCb && !mType->validatorCb(selection)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the measurement type prioritizes the given selection
|
||||
if (mType->prioritizeCb && mType->prioritizeCb(selection)) {
|
||||
validTypes.insert(validTypes.begin(), mType);
|
||||
} else {
|
||||
validTypes.push_back(mType);
|
||||
}
|
||||
|
||||
// Check if the measurement type prioritizes the given selection
|
||||
if (mType->prioritizeCb && mType->prioritizeCb(selection)) {
|
||||
validTypes.insert(validTypes.begin(), mType);
|
||||
}
|
||||
else {
|
||||
validTypes.push_back(mType);
|
||||
}
|
||||
}
|
||||
|
||||
return validTypes;
|
||||
}
|
||||
|
||||
return validTypes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace App
|
||||
} // namespace App
|
||||
|
||||
@@ -36,24 +36,27 @@
|
||||
|
||||
#include <FCGlobal.h>
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
|
||||
// Add your class methods and member variables here
|
||||
enum class MeasureElementType {
|
||||
enum class MeasureElementType
|
||||
{
|
||||
INVALID,
|
||||
POINT,
|
||||
LINE,
|
||||
LINESEGMENT,
|
||||
CIRCLE,
|
||||
ARC,
|
||||
CURVE, // Has a length but no radius or axis
|
||||
CURVE, // Has a length but no radius or axis
|
||||
PLANE,
|
||||
CYLINDER,
|
||||
Volume,
|
||||
};
|
||||
|
||||
|
||||
struct MeasureSelectionItem {
|
||||
struct MeasureSelectionItem
|
||||
{
|
||||
App::SubObjectT object;
|
||||
Base::Vector3d pickedPoint;
|
||||
};
|
||||
@@ -62,9 +65,10 @@ struct MeasureSelectionItem {
|
||||
using MeasureSelection = std::vector<MeasureSelectionItem>;
|
||||
using MeasureValidateMethod = std::function<bool(const MeasureSelection&)>;
|
||||
using MeasurePrioritizeMethod = std::function<bool(const MeasureSelection&)>;
|
||||
using MeasureTypeMethod = std::function<MeasureElementType (App::DocumentObject*, const char*)>;
|
||||
using MeasureTypeMethod = std::function<MeasureElementType(App::DocumentObject*, const char*)>;
|
||||
|
||||
struct MeasureType {
|
||||
struct MeasureType
|
||||
{
|
||||
std::string identifier;
|
||||
std::string label;
|
||||
std::string measureObject;
|
||||
@@ -72,21 +76,24 @@ struct MeasureType {
|
||||
// Checks if the measurement works with a given selection
|
||||
MeasureValidateMethod validatorCb;
|
||||
|
||||
// Allows to prioritize this over other measurement types when the measurement type is picked implicitly from the selection.
|
||||
// Gets called only when validatorCb returned true for the given selection
|
||||
// Allows to prioritize this over other measurement types when the measurement type is picked
|
||||
// implicitly from the selection. Gets called only when validatorCb returned true for the given
|
||||
// selection
|
||||
MeasurePrioritizeMethod prioritizeCb;
|
||||
|
||||
bool isPython;
|
||||
PyObject* pythonClass;
|
||||
};
|
||||
|
||||
struct MeasureHandler {
|
||||
struct MeasureHandler
|
||||
{
|
||||
std::string module;
|
||||
MeasureTypeMethod typeCb;
|
||||
};
|
||||
|
||||
|
||||
class AppExport MeasureManager {
|
||||
class AppExport MeasureManager
|
||||
{
|
||||
public:
|
||||
MeasureManager();
|
||||
|
||||
@@ -96,11 +103,20 @@ public:
|
||||
static MeasureHandler getMeasureHandler(const App::MeasureSelectionItem& selectionItem);
|
||||
static MeasureElementType getMeasureElementType(const App::MeasureSelectionItem& selectionItem);
|
||||
static void addMeasureType(MeasureType* measureType);
|
||||
static void addMeasureType(std::string id, std::string label, std::string measureObj, MeasureValidateMethod validatorCb, MeasurePrioritizeMethod prioritizeCb);
|
||||
static void addMeasureType(const char* id, const char* label, const char* measureObj, MeasureValidateMethod validatorCb, MeasurePrioritizeMethod prioritizeCb);
|
||||
static void addMeasureType(std::string id,
|
||||
std::string label,
|
||||
std::string measureObj,
|
||||
MeasureValidateMethod validatorCb,
|
||||
MeasurePrioritizeMethod prioritizeCb);
|
||||
static void addMeasureType(const char* id,
|
||||
const char* label,
|
||||
const char* measureObj,
|
||||
MeasureValidateMethod validatorCb,
|
||||
MeasurePrioritizeMethod prioritizeCb);
|
||||
static const std::vector<MeasureType*> getMeasureTypes();
|
||||
static Py::Tuple getSelectionPy(const App::MeasureSelection& selection);
|
||||
static std::vector<MeasureType*> getValidMeasureTypes(App::MeasureSelection selection, std::string mode);
|
||||
static std::vector<MeasureType*> getValidMeasureTypes(App::MeasureSelection selection,
|
||||
std::string mode);
|
||||
|
||||
|
||||
private:
|
||||
@@ -109,6 +125,6 @@ private:
|
||||
};
|
||||
|
||||
|
||||
} // namespace App
|
||||
} // namespace App
|
||||
|
||||
#endif // MEASUREMANAGER_H
|
||||
#endif // MEASUREMANAGER_H
|
||||
|
||||
@@ -47,17 +47,17 @@ int MeasureManagerPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*
|
||||
}
|
||||
|
||||
|
||||
PyObject* MeasureManagerPy::addMeasureType(PyObject *args)
|
||||
PyObject* MeasureManagerPy::addMeasureType(PyObject* args)
|
||||
{
|
||||
PyObject *pyobj = Py_None;
|
||||
PyObject* pyobj = Py_None;
|
||||
char *id, *label;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ssO", &id, &label, &pyobj))
|
||||
if (!PyArg_ParseTuple(args, "ssO", &id, &label, &pyobj)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MeasureManager::addMeasureType(
|
||||
new App::MeasureType{id, label, "", nullptr, nullptr, true, pyobj}
|
||||
);
|
||||
new App::MeasureType {id, label, "", nullptr, nullptr, true, pyobj});
|
||||
|
||||
Py_Return;
|
||||
}
|
||||
@@ -66,7 +66,7 @@ PyObject* MeasureManagerPy::addMeasureType(PyObject *args)
|
||||
PyObject* MeasureManagerPy::getMeasureTypes()
|
||||
{
|
||||
Py::List types;
|
||||
for (auto & it : MeasureManager::getMeasureTypes()) {
|
||||
for (auto& it : MeasureManager::getMeasureTypes()) {
|
||||
Py::Tuple type(3);
|
||||
type.setItem(0, Py::String(it->identifier));
|
||||
type.setItem(1, Py::String(it->label));
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
# include <stack>
|
||||
#include <stack>
|
||||
#endif
|
||||
|
||||
#include <QCoreApplication>
|
||||
@@ -36,13 +36,17 @@
|
||||
using namespace App;
|
||||
namespace sp = std::placeholders;
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
|
||||
class XMLMergeReader : public Base::XMLReader
|
||||
class XMLMergeReader: public Base::XMLReader
|
||||
{
|
||||
public:
|
||||
XMLMergeReader(std::map<std::string, std::string>& name, const char* FileName, std::istream& str)
|
||||
: Base::XMLReader(FileName, str), nameMap(name)
|
||||
XMLMergeReader(std::map<std::string, std::string>& name,
|
||||
const char* FileName,
|
||||
std::istream& str)
|
||||
: Base::XMLReader(FileName, str)
|
||||
, nameMap(name)
|
||||
{}
|
||||
|
||||
void addName(const char* s1, const char* s2) override
|
||||
@@ -52,34 +56,35 @@ public:
|
||||
const char* getName(const char* name) const override
|
||||
{
|
||||
std::map<std::string, std::string>::const_iterator it = nameMap.find(name);
|
||||
if (it != nameMap.end())
|
||||
if (it != nameMap.end()) {
|
||||
return it->second.c_str();
|
||||
else
|
||||
}
|
||||
else {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
bool doNameMapping() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string>& nameMap;
|
||||
using PropertyTag = std::pair<std::string, std::string>;
|
||||
std::stack<PropertyTag> propertyStack;
|
||||
};
|
||||
}
|
||||
} // namespace App
|
||||
|
||||
MergeDocuments::MergeDocuments(App::Document* doc)
|
||||
: appdoc(doc)
|
||||
{
|
||||
//NOLINTBEGIN
|
||||
connectExport = doc->signalExportObjects.connect
|
||||
(std::bind(&MergeDocuments::exportObject, this, sp::_1, sp::_2));
|
||||
connectImport = doc->signalImportObjects.connect
|
||||
(std::bind(&MergeDocuments::importObject, this, sp::_1, sp::_2));
|
||||
//NOLINTEND
|
||||
// NOLINTBEGIN
|
||||
connectExport = doc->signalExportObjects.connect(
|
||||
std::bind(&MergeDocuments::exportObject, this, sp::_1, sp::_2));
|
||||
connectImport = doc->signalImportObjects.connect(
|
||||
std::bind(&MergeDocuments::importObject, this, sp::_1, sp::_2));
|
||||
// NOLINTEND
|
||||
|
||||
QCoreApplication* app = QCoreApplication::instance();
|
||||
if (app && app->inherits("QApplication")) {
|
||||
@@ -93,17 +98,16 @@ MergeDocuments::~MergeDocuments()
|
||||
connectImport.disconnect();
|
||||
}
|
||||
|
||||
unsigned int MergeDocuments::getMemSize () const
|
||||
unsigned int MergeDocuments::getMemSize() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*>
|
||||
MergeDocuments::importObjects(std::istream& input)
|
||||
std::vector<App::DocumentObject*> MergeDocuments::importObjects(std::istream& input)
|
||||
{
|
||||
this->nameMap.clear();
|
||||
this->stream = new zipios::ZipInputStream(input);
|
||||
XMLMergeReader reader(this->nameMap,"<memory>", *stream);
|
||||
XMLMergeReader reader(this->nameMap, "<memory>", *stream);
|
||||
reader.setVerbose(isVerbose());
|
||||
std::vector<App::DocumentObject*> objs = appdoc->importObjects(reader);
|
||||
|
||||
@@ -113,20 +117,20 @@ MergeDocuments::importObjects(std::istream& input)
|
||||
return objs;
|
||||
}
|
||||
|
||||
void MergeDocuments::importObject(const std::vector<App::DocumentObject*>& o, Base::XMLReader & r)
|
||||
void MergeDocuments::importObject(const std::vector<App::DocumentObject*>& o, Base::XMLReader& r)
|
||||
{
|
||||
objects = o;
|
||||
Restore(r);
|
||||
r.readFiles(*this->stream);
|
||||
}
|
||||
|
||||
void MergeDocuments::exportObject(const std::vector<App::DocumentObject*>& o, Base::Writer & w)
|
||||
void MergeDocuments::exportObject(const std::vector<App::DocumentObject*>& o, Base::Writer& w)
|
||||
{
|
||||
objects = o;
|
||||
Save(w);
|
||||
}
|
||||
|
||||
void MergeDocuments::Save (Base::Writer & w) const
|
||||
void MergeDocuments::Save(Base::Writer& w) const
|
||||
{
|
||||
// Save view provider stuff
|
||||
if (guiup) {
|
||||
@@ -134,7 +138,7 @@ void MergeDocuments::Save (Base::Writer & w) const
|
||||
}
|
||||
}
|
||||
|
||||
void MergeDocuments::Restore(Base::XMLReader &r)
|
||||
void MergeDocuments::Restore(Base::XMLReader& r)
|
||||
{
|
||||
// Restore view provider stuff
|
||||
if (guiup) {
|
||||
@@ -142,13 +146,13 @@ void MergeDocuments::Restore(Base::XMLReader &r)
|
||||
}
|
||||
}
|
||||
|
||||
void MergeDocuments::SaveDocFile (Base::Writer & w) const
|
||||
void MergeDocuments::SaveDocFile(Base::Writer& w) const
|
||||
{
|
||||
// Save view provider stuff
|
||||
appdoc->signalExportViewObjects(this->objects, w);
|
||||
}
|
||||
|
||||
void MergeDocuments::RestoreDocFile(Base::Reader & r)
|
||||
void MergeDocuments::RestoreDocFile(Base::Reader& r)
|
||||
{
|
||||
// Restore view provider stuff
|
||||
appdoc->signalImportViewObjects(this->objects, r, this->nameMap);
|
||||
|
||||
@@ -27,36 +27,47 @@
|
||||
#include <Base/Persistence.h>
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
namespace zipios {
|
||||
namespace zipios
|
||||
{
|
||||
class ZipInputStream;
|
||||
}
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
class Document;
|
||||
class DocumentObject;
|
||||
class AppExport MergeDocuments : public Base::Persistence
|
||||
class AppExport MergeDocuments: public Base::Persistence
|
||||
{
|
||||
public:
|
||||
explicit MergeDocuments(App::Document* doc);
|
||||
~MergeDocuments() override;
|
||||
bool isVerbose() const { return verbose; }
|
||||
void setVerbose(bool on) { verbose = on; }
|
||||
unsigned int getMemSize () const override;
|
||||
bool isVerbose() const
|
||||
{
|
||||
return verbose;
|
||||
}
|
||||
void setVerbose(bool on)
|
||||
{
|
||||
verbose = on;
|
||||
}
|
||||
unsigned int getMemSize() const override;
|
||||
std::vector<App::DocumentObject*> importObjects(std::istream&);
|
||||
void importObject(const std::vector<App::DocumentObject*>& o, Base::XMLReader & r);
|
||||
void exportObject(const std::vector<App::DocumentObject*>& o, Base::Writer & w);
|
||||
void Save (Base::Writer & w) const override;
|
||||
void Restore(Base::XMLReader &r) override;
|
||||
void SaveDocFile (Base::Writer & w) const override;
|
||||
void RestoreDocFile(Base::Reader & r) override;
|
||||
void importObject(const std::vector<App::DocumentObject*>& o, Base::XMLReader& r);
|
||||
void exportObject(const std::vector<App::DocumentObject*>& o, Base::Writer& w);
|
||||
void Save(Base::Writer& w) const override;
|
||||
void Restore(Base::XMLReader& r) override;
|
||||
void SaveDocFile(Base::Writer& w) const override;
|
||||
void RestoreDocFile(Base::Reader& r) override;
|
||||
|
||||
const std::map<std::string, std::string> &getNameMap() const {return nameMap;}
|
||||
const std::map<std::string, std::string>& getNameMap() const
|
||||
{
|
||||
return nameMap;
|
||||
}
|
||||
|
||||
private:
|
||||
bool guiup{false};
|
||||
bool verbose{true};
|
||||
zipios::ZipInputStream* stream{nullptr};
|
||||
App::Document* appdoc{nullptr};
|
||||
bool guiup {false};
|
||||
bool verbose {true};
|
||||
zipios::ZipInputStream* stream {nullptr};
|
||||
App::Document* appdoc {nullptr};
|
||||
std::vector<App::DocumentObject*> objects;
|
||||
std::map<std::string, std::string> nameMap;
|
||||
using Connection = boost::signals2::connection;
|
||||
@@ -64,6 +75,6 @@ private:
|
||||
Connection connectImport;
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_MERGEDOCUMENTS_H
|
||||
#endif // APP_MERGEDOCUMENTS_H
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
/**************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2021-2023 FreeCAD Project Association *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
* *
|
||||
* Copyright (c) 2021-2023 FreeCAD Project Association *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <boost/core/ignore_unused.hpp>
|
||||
# include <memory>
|
||||
# include <sstream>
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#endif
|
||||
|
||||
#include <xercesc/framework/LocalFileFormatTarget.hpp>
|
||||
@@ -93,7 +93,7 @@ class XMLErrorHandler: public HandlerBase
|
||||
throw Base::XMLBaseException(message.str());
|
||||
}
|
||||
};
|
||||
}// namespace MetadataInternal
|
||||
} // namespace MetadataInternal
|
||||
|
||||
Metadata::Metadata(const fs::path& metadataFile)
|
||||
: _dom(nullptr)
|
||||
@@ -130,10 +130,9 @@ Metadata::Metadata(const DOMNode* domNode, int format)
|
||||
App::Metadata::Metadata(const std::string& rawData)
|
||||
: _dom(nullptr)
|
||||
{
|
||||
MemBufInputSource buffer(
|
||||
reinterpret_cast<const XMLByte*>(rawData.c_str()),
|
||||
rawData.size(),
|
||||
"raw data (in memory)");
|
||||
MemBufInputSource buffer(reinterpret_cast<const XMLByte*>(rawData.c_str()),
|
||||
rawData.size(),
|
||||
"raw data (in memory)");
|
||||
loadFromInputSource(buffer);
|
||||
}
|
||||
|
||||
@@ -294,7 +293,7 @@ XERCES_CPP_NAMESPACE::DOMElement* Metadata::dom() const
|
||||
|
||||
void Metadata::setName(const std::string& name)
|
||||
{
|
||||
std::string invalidCharacters = "/\\?%*:|\"<>";// Should cover all OSes
|
||||
std::string invalidCharacters = "/\\?%*:|\"<>"; // Should cover all OSes
|
||||
if (_name.find_first_of(invalidCharacters) != std::string::npos) {
|
||||
throw Base::RuntimeError("Name cannot contain any of: " + invalidCharacters);
|
||||
}
|
||||
@@ -534,7 +533,8 @@ void Metadata::clearFile()
|
||||
}
|
||||
|
||||
|
||||
DOMElement* appendSimpleXMLNode(DOMElement* baseNode, const std::string& nodeName,
|
||||
DOMElement* appendSimpleXMLNode(DOMElement* baseNode,
|
||||
const std::string& nodeName,
|
||||
const std::string& nodeContents)
|
||||
{
|
||||
// For convenience (and brevity of final output) don't create nodes that don't have contents
|
||||
@@ -665,8 +665,9 @@ bool Metadata::satisfies(const Meta::Dependency& dep)
|
||||
if (dep.package != _name) {
|
||||
return false;
|
||||
}
|
||||
// The "condition" attribute allows an expression to enable or disable this dependency check: it must contain a valid
|
||||
// FreeCAD Expression. If it evaluates to false, this dependency is bypassed (e.g. this function returns false).
|
||||
// The "condition" attribute allows an expression to enable or disable this dependency check: it
|
||||
// must contain a valid FreeCAD Expression. If it evaluates to false, this dependency is
|
||||
// bypassed (e.g. this function returns false).
|
||||
if (!dep.condition.empty()) {
|
||||
auto injectedString = dep.condition;
|
||||
std::map<std::string, std::string> replacements;
|
||||
@@ -938,11 +939,11 @@ void Metadata::parseVersion1(const DOMNode* startNode)
|
||||
_icon = fs::path(StrXUTF8(element->getTextContent()).str);
|
||||
}
|
||||
else if (tagString == "content") {
|
||||
parseContentNodeVersion1(element);// Recursive call
|
||||
parseContentNodeVersion1(element); // Recursive call
|
||||
}
|
||||
else {
|
||||
// If none of this node's nodeChildren have nodeChildren of their own, it is a simple element and we
|
||||
// can handle it as a GenericMetadata object
|
||||
// If none of this node's nodeChildren have nodeChildren of their own, it is a simple
|
||||
// element and we can handle it as a GenericMetadata object
|
||||
auto nodeChildren = element->getChildNodes();
|
||||
bool hasGrandchildren = false;
|
||||
for (XMLSize_t j = 0; j < nodeChildren->getLength() && !hasGrandchildren; ++j) {
|
||||
@@ -970,15 +971,15 @@ void Metadata::parseContentNodeVersion1(const DOMElement* contentNode)
|
||||
}
|
||||
|
||||
Meta::Contact::Contact(std::string name, std::string email)
|
||||
: name(std::move(name)),
|
||||
email(std::move(email))
|
||||
: name(std::move(name))
|
||||
, email(std::move(email))
|
||||
{
|
||||
// This has to be provided manually since we have another constructor
|
||||
}
|
||||
|
||||
Meta::Contact::Contact(const XERCES_CPP_NAMESPACE::DOMElement* elem)
|
||||
{
|
||||
if (!elem){
|
||||
if (!elem) {
|
||||
return;
|
||||
}
|
||||
auto emailAttribute = elem->getAttribute(XUTF8Str("email").unicodeForm());
|
||||
@@ -992,15 +993,15 @@ bool App::Meta::Contact::operator==(const Contact& rhs) const
|
||||
}
|
||||
|
||||
Meta::License::License(std::string name, fs::path file)
|
||||
: name(std::move(name)),
|
||||
file(std::move(file))
|
||||
: name(std::move(name))
|
||||
, file(std::move(file))
|
||||
{
|
||||
// This has to be provided manually since we have another constructor
|
||||
}
|
||||
|
||||
Meta::License::License(const XERCES_CPP_NAMESPACE::DOMElement* elem)
|
||||
{
|
||||
if (!elem){
|
||||
if (!elem) {
|
||||
return;
|
||||
}
|
||||
auto fileAttribute = elem->getAttribute(XUTF8Str("file").unicodeForm());
|
||||
@@ -1016,13 +1017,13 @@ bool App::Meta::License::operator==(const License& rhs) const
|
||||
}
|
||||
|
||||
App::Meta::Url::Url()
|
||||
: location(""),
|
||||
type(App::Meta::UrlType::website)
|
||||
: location("")
|
||||
, type(App::Meta::UrlType::website)
|
||||
{}
|
||||
|
||||
Meta::Url::Url(std::string location, UrlType type)
|
||||
: location(std::move(location)),
|
||||
type(type)
|
||||
: location(std::move(location))
|
||||
, type(type)
|
||||
{
|
||||
// This has to be provided manually since we have another constructor
|
||||
}
|
||||
@@ -1070,14 +1071,14 @@ bool App::Meta::Url::operator==(const Url& rhs) const
|
||||
}
|
||||
|
||||
App::Meta::Dependency::Dependency()
|
||||
: optional(false),
|
||||
dependencyType(App::Meta::DependencyType::automatic)
|
||||
: optional(false)
|
||||
, dependencyType(App::Meta::DependencyType::automatic)
|
||||
{}
|
||||
|
||||
App::Meta::Dependency::Dependency(std::string pkg)
|
||||
: package(std::move(pkg)),
|
||||
optional(false),
|
||||
dependencyType(App::Meta::DependencyType::automatic)
|
||||
: package(std::move(pkg))
|
||||
, optional(false)
|
||||
, dependencyType(App::Meta::DependencyType::automatic)
|
||||
{}
|
||||
|
||||
Meta::Dependency::Dependency(const XERCES_CPP_NAMESPACE::DOMElement* elem)
|
||||
@@ -1090,7 +1091,7 @@ Meta::Dependency::Dependency(const XERCES_CPP_NAMESPACE::DOMElement* elem)
|
||||
condition = StrXUTF8(elem->getAttribute(XUTF8Str("condition").unicodeForm())).str;
|
||||
std::string opt_string = StrXUTF8(elem->getAttribute(XUTF8Str("optional").unicodeForm())).str;
|
||||
if (opt_string == "true"
|
||||
|| opt_string == "True") {// Support Python capitalization in this one case...
|
||||
|| opt_string == "True") { // Support Python capitalization in this one case...
|
||||
optional = true;
|
||||
}
|
||||
else {
|
||||
@@ -1128,10 +1129,10 @@ bool App::Meta::Dependency::operator==(const Dependency& rhs) const
|
||||
Meta::Version::Version() = default;
|
||||
|
||||
Meta::Version::Version(int major, int minor, int patch, std::string suffix)
|
||||
: major(major),
|
||||
minor(minor),
|
||||
patch(patch),
|
||||
suffix(std::move(suffix))
|
||||
: major(major)
|
||||
, minor(minor)
|
||||
, patch(patch)
|
||||
, suffix(std::move(suffix))
|
||||
{}
|
||||
|
||||
Meta::Version::Version(const std::string& versionString)
|
||||
@@ -1207,8 +1208,8 @@ Meta::GenericMetadata::GenericMetadata(const XERCES_CPP_NAMESPACE::DOMElement* e
|
||||
contents = StrXUTF8(elem->getTextContent()).str;
|
||||
for (XMLSize_t i = 0; i < elem->getAttributes()->getLength(); ++i) {
|
||||
auto attr = elem->getAttributes()->item(i);
|
||||
attributes.insert(
|
||||
std::make_pair(StrXUTF8(attr->getNodeName()).str, StrXUTF8(attr->getTextContent()).str));
|
||||
attributes.insert(std::make_pair(StrXUTF8(attr->getNodeName()).str,
|
||||
StrXUTF8(attr->getTextContent()).str));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
/**************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2021-2023 FreeCAD Project Association *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
* *
|
||||
* Copyright (c) 2021-2023 FreeCAD Project Association *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef BASE_METADATAREADER_H
|
||||
#define BASE_METADATAREADER_H
|
||||
@@ -43,32 +43,36 @@ namespace Meta
|
||||
{
|
||||
|
||||
/**
|
||||
* \struct Contact
|
||||
* \brief A person or company representing a point of contact for the package (either author or maintainer).
|
||||
*/
|
||||
struct AppExport Contact {
|
||||
* \struct Contact
|
||||
* \brief A person or company representing a point of contact for the package (either author or
|
||||
* maintainer).
|
||||
*/
|
||||
struct AppExport Contact
|
||||
{
|
||||
Contact() = default;
|
||||
Contact(std::string name, std::string email);
|
||||
Contact(std::string name, std::string email);
|
||||
explicit Contact(const XERCES_CPP_NAMESPACE::DOMElement* elem);
|
||||
std::string name; //< Contact name - required
|
||||
std::string email;//< Contact email - may be optional
|
||||
std::string name; //< Contact name - required
|
||||
std::string email; //< Contact email - may be optional
|
||||
bool operator==(const Contact& rhs) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct License
|
||||
* \brief A license that covers some or all of this package.
|
||||
*
|
||||
* Many licenses also require the inclusion of the complete license text, specified in this struct
|
||||
* using the "file" member.
|
||||
*/
|
||||
struct AppExport License {
|
||||
* \struct License
|
||||
* \brief A license that covers some or all of this package.
|
||||
*
|
||||
* Many licenses also require the inclusion of the complete license text, specified in this struct
|
||||
* using the "file" member.
|
||||
*/
|
||||
struct AppExport License
|
||||
{
|
||||
License() = default;
|
||||
License(std::string name, boost::filesystem::path file);
|
||||
explicit License(const XERCES_CPP_NAMESPACE::DOMElement* elem);
|
||||
std::string name;//< Short name of license, e.g. "LGPL2", "MIT", "Mozilla Public License", etc.
|
||||
std::string
|
||||
name; //< Short name of license, e.g. "LGPL2", "MIT", "Mozilla Public License", etc.
|
||||
boost::filesystem::path
|
||||
file;//< Optional path to the license file, relative to the XML file's location
|
||||
file; //< Optional path to the license file, relative to the XML file's location
|
||||
bool operator==(const License& rhs) const;
|
||||
};
|
||||
|
||||
@@ -83,32 +87,35 @@ enum class UrlType
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct Url
|
||||
* \brief A URL, including type information (e.g. website, repository, or bugtracker, in package.xml)
|
||||
*/
|
||||
struct AppExport Url {
|
||||
* \struct Url
|
||||
* \brief A URL, including type information (e.g. website, repository, or bugtracker, in
|
||||
* package.xml)
|
||||
*/
|
||||
struct AppExport Url
|
||||
{
|
||||
Url();
|
||||
Url(std::string location, UrlType type);
|
||||
explicit Url(const XERCES_CPP_NAMESPACE::DOMElement* elem);
|
||||
std::string location;//< The actual URL, including protocol
|
||||
UrlType type; //< What kind of URL this is
|
||||
std::string branch; //< If it's a repository, which branch to use
|
||||
std::string location; //< The actual URL, including protocol
|
||||
UrlType type; //< What kind of URL this is
|
||||
std::string branch; //< If it's a repository, which branch to use
|
||||
bool operator==(const Url& rhs) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct Version
|
||||
* A semantic version structure providing comparison operators and conversion to and from std::string
|
||||
*/
|
||||
struct AppExport Version {
|
||||
* \struct Version
|
||||
* A semantic version structure providing comparison operators and conversion to and from
|
||||
* std::string
|
||||
*/
|
||||
struct AppExport Version
|
||||
{
|
||||
Version();
|
||||
explicit Version(int major, int minor = 0, int patch = 0,
|
||||
std::string suffix = std::string());
|
||||
explicit Version(int major, int minor = 0, int patch = 0, std::string suffix = std::string());
|
||||
explicit Version(const std::string& semanticString);
|
||||
|
||||
int major{};
|
||||
int minor{};
|
||||
int patch{};
|
||||
int major {};
|
||||
int minor {};
|
||||
int patch {};
|
||||
std::string suffix;
|
||||
|
||||
std::string str() const;
|
||||
@@ -122,9 +129,9 @@ struct AppExport Version {
|
||||
};
|
||||
|
||||
/**
|
||||
* \enum DependencyType
|
||||
* The type of dependency.
|
||||
*/
|
||||
* \enum DependencyType
|
||||
* The type of dependency.
|
||||
*/
|
||||
enum class DependencyType
|
||||
{
|
||||
automatic,
|
||||
@@ -134,81 +141,83 @@ enum class DependencyType
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct Dependency
|
||||
* \brief Another package that this package depends on, conflicts with, or replaces
|
||||
*/
|
||||
struct AppExport Dependency {
|
||||
* \struct Dependency
|
||||
* \brief Another package that this package depends on, conflicts with, or replaces
|
||||
*/
|
||||
struct AppExport Dependency
|
||||
{
|
||||
Dependency();
|
||||
explicit Dependency(std::string pkg);
|
||||
explicit Dependency(std::string pkg);
|
||||
explicit Dependency(const XERCES_CPP_NAMESPACE::DOMElement* elem);
|
||||
std::string
|
||||
package;//< Required: must exactly match the contents of the "name" element in the referenced package's package.xml file.
|
||||
std::string
|
||||
version_lt;//< Optional: The dependency to the package is restricted to versions less than the stated version number.
|
||||
std::string
|
||||
version_lte;//< Optional: The dependency to the package is restricted to versions less or equal than the stated version number.
|
||||
std::string
|
||||
version_eq;//< Optional: The dependency to the package is restricted to a version equal than the stated version number.
|
||||
std::string
|
||||
version_gte;//< Optional: The dependency to the package is restricted to versions greater or equal than the stated version number.
|
||||
std::string
|
||||
version_gt;//< Optional: The dependency to the package is restricted to versions greater than the stated version number.
|
||||
std::string condition; //< Optional: Conditional expression as documented in REP149.
|
||||
bool optional; //< Optional: Whether this dependency is considered "optional"
|
||||
DependencyType dependencyType;//< Optional: defaults to "automatic"
|
||||
std::string package; //< Required: must exactly match the contents of the "name" element in the
|
||||
//referenced package's package.xml file.
|
||||
std::string version_lt; //< Optional: The dependency to the package is restricted to versions
|
||||
//less than the stated version number.
|
||||
std::string version_lte; //< Optional: The dependency to the package is restricted to versions
|
||||
//less or equal than the stated version number.
|
||||
std::string version_eq; //< Optional: The dependency to the package is restricted to a version
|
||||
//equal than the stated version number.
|
||||
std::string version_gte; //< Optional: The dependency to the package is restricted to versions
|
||||
//greater or equal than the stated version number.
|
||||
std::string version_gt; //< Optional: The dependency to the package is restricted to versions
|
||||
//greater than the stated version number.
|
||||
std::string condition; //< Optional: Conditional expression as documented in REP149.
|
||||
bool optional; //< Optional: Whether this dependency is considered "optional"
|
||||
DependencyType dependencyType; //< Optional: defaults to "automatic"
|
||||
bool operator==(const Dependency& rhs) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct GenericMetadata
|
||||
* A structure to hold unrecognized single-level metadata.
|
||||
*
|
||||
* Most unrecognized metadata is simple: when parsing the XML, if the parser finds a tag it
|
||||
* does not recognize, and that tag has no children, it is parsed into this data structure
|
||||
* for convenient access by client code.
|
||||
*/
|
||||
struct AppExport GenericMetadata {
|
||||
* \struct GenericMetadata
|
||||
* A structure to hold unrecognized single-level metadata.
|
||||
*
|
||||
* Most unrecognized metadata is simple: when parsing the XML, if the parser finds a tag it
|
||||
* does not recognize, and that tag has no children, it is parsed into this data structure
|
||||
* for convenient access by client code.
|
||||
*/
|
||||
struct AppExport GenericMetadata
|
||||
{
|
||||
GenericMetadata() = default;
|
||||
explicit GenericMetadata(const XERCES_CPP_NAMESPACE::DOMElement* elem);
|
||||
explicit GenericMetadata(std::string contents);
|
||||
std::string contents; //< The contents of the tag
|
||||
std::map<std::string, std::string> attributes;//< The XML attributes of the tag
|
||||
explicit GenericMetadata(std::string contents);
|
||||
std::string contents; //< The contents of the tag
|
||||
std::map<std::string, std::string> attributes; //< The XML attributes of the tag
|
||||
};
|
||||
|
||||
}// namespace Meta
|
||||
} // namespace Meta
|
||||
|
||||
/**
|
||||
* \class Metadata
|
||||
* \brief Reads data from a metadata file.
|
||||
*
|
||||
* The metadata format is based on https://ros.org/reps/rep-0149.html, modified for FreeCAD
|
||||
* use. Full format documentation is available at the FreeCAD Wiki:
|
||||
* https://wiki.freecad.org/Package_Metadata
|
||||
*/
|
||||
* \class Metadata
|
||||
* \brief Reads data from a metadata file.
|
||||
*
|
||||
* The metadata format is based on https://ros.org/reps/rep-0149.html, modified for FreeCAD
|
||||
* use. Full format documentation is available at the FreeCAD Wiki:
|
||||
* https://wiki.freecad.org/Package_Metadata
|
||||
*/
|
||||
class AppExport Metadata
|
||||
{
|
||||
public:
|
||||
Metadata();
|
||||
|
||||
/**
|
||||
* Read the data from a file on disk
|
||||
*
|
||||
* This constructor takes a path to an XML file and loads the XML from that file as
|
||||
* metadata.
|
||||
*/
|
||||
* Read the data from a file on disk
|
||||
*
|
||||
* This constructor takes a path to an XML file and loads the XML from that file as
|
||||
* metadata.
|
||||
*/
|
||||
explicit Metadata(const boost::filesystem::path& metadataFile);
|
||||
|
||||
/**
|
||||
* Construct a Metadata object from a DOM node.
|
||||
*
|
||||
* This node may have any tag name: it is only accessed via its children, which are
|
||||
* expected to follow the standard Metadata format for the contents of the <package> element.
|
||||
*/
|
||||
* Construct a Metadata object from a DOM node.
|
||||
*
|
||||
* This node may have any tag name: it is only accessed via its children, which are
|
||||
* expected to follow the standard Metadata format for the contents of the <package> element.
|
||||
*/
|
||||
Metadata(const XERCES_CPP_NAMESPACE::DOMNode* domNode, int format);
|
||||
|
||||
/**
|
||||
* Treat the incoming rawData as metadata to be parsed.
|
||||
*/
|
||||
* Treat the incoming rawData as metadata to be parsed.
|
||||
*/
|
||||
explicit Metadata(const std::string& rawData);
|
||||
|
||||
~Metadata();
|
||||
@@ -218,69 +227,69 @@ public:
|
||||
// Recognized Metadata
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
std::string name() const; //< A short name for this package, often used as a menu entry.
|
||||
std::string type() const; //< The type for this package.
|
||||
Meta::Version version() const;//< Version string in semantic triplet format, e.g. "1.2.3".
|
||||
std::string name() const; //< A short name for this package, often used as a menu entry.
|
||||
std::string type() const; //< The type for this package.
|
||||
Meta::Version version() const; //< Version string in semantic triplet format, e.g. "1.2.3".
|
||||
std::string date()
|
||||
const;//< Date string -- currently arbitrary (when C++20 is well-supported we can revisit)
|
||||
std::string description() const;//< Text-only description of the package. No markup.
|
||||
const; //< Date string -- currently arbitrary (when C++20 is well-supported we can revisit)
|
||||
std::string description() const; //< Text-only description of the package. No markup.
|
||||
std::vector<Meta::Contact>
|
||||
maintainer() const;//< Must be at least one, and must specify an email address.
|
||||
maintainer() const; //< Must be at least one, and must specify an email address.
|
||||
std::vector<Meta::License>
|
||||
license() const;//< Must be at least one, and most licenses require including a license file.
|
||||
std::vector<Meta::Url> url()
|
||||
const;//< Any number of URLs may be specified, but at least one repository URL must be included at the package level.
|
||||
license() const; //< Must be at least one, and most licenses require including a license file.
|
||||
std::vector<Meta::Url> url() const; //< Any number of URLs may be specified, but at least one
|
||||
//repository URL must be included at the package level.
|
||||
std::vector<Meta::Contact>
|
||||
author() const;//< Any number of authors may be specified, and email addresses are optional.
|
||||
author() const; //< Any number of authors may be specified, and email addresses are optional.
|
||||
std::vector<Meta::Dependency>
|
||||
depend() const;//< Zero or more packages this package requires prior to use.
|
||||
depend() const; //< Zero or more packages this package requires prior to use.
|
||||
std::vector<Meta::Dependency>
|
||||
conflict() const;//< Zero of more packages this package conflicts with.
|
||||
conflict() const; //< Zero of more packages this package conflicts with.
|
||||
std::vector<Meta::Dependency>
|
||||
replace() const;//< Zero or more packages this package is intended to replace.
|
||||
std::vector<std::string> tag() const;//< Zero or more text tags related to this package.
|
||||
boost::filesystem::path icon() const;//< Path to an icon file.
|
||||
replace() const; //< Zero or more packages this package is intended to replace.
|
||||
std::vector<std::string> tag() const; //< Zero or more text tags related to this package.
|
||||
boost::filesystem::path icon() const; //< Path to an icon file.
|
||||
std::string
|
||||
classname() const;//< Recognized for convenience -- generally only used by Workbenches.
|
||||
classname() const; //< Recognized for convenience -- generally only used by Workbenches.
|
||||
boost::filesystem::path
|
||||
subdirectory() const;//< Optional, override the default subdirectory name for this item.
|
||||
subdirectory() const; //< Optional, override the default subdirectory name for this item.
|
||||
std::vector<boost::filesystem::path>
|
||||
file() const;//< Arbitrary files associated with this package or content item.
|
||||
Meta::Version freecadmin() const;//< The minimum FreeCAD version.
|
||||
Meta::Version freecadmax() const;//< The maximum FreeCAD version.
|
||||
Meta::Version pythonmin() const; //< The minimum Python version.
|
||||
file() const; //< Arbitrary files associated with this package or content item.
|
||||
Meta::Version freecadmin() const; //< The minimum FreeCAD version.
|
||||
Meta::Version freecadmax() const; //< The maximum FreeCAD version.
|
||||
Meta::Version pythonmin() const; //< The minimum Python version.
|
||||
|
||||
/**
|
||||
* Access the metadata for the content elements of this package
|
||||
*
|
||||
* In addition to the overall package metadata, this class reads in metadata contained in a
|
||||
* <content> element. Each entry in the content element is an element representing some
|
||||
* type of package content (e.g. add-on, macro, theme, etc.). This class places no restriction
|
||||
* on the types, it is up to client code to place requirements on the metadata included
|
||||
* here.
|
||||
*
|
||||
* For example, themes might be specified:
|
||||
* <content>
|
||||
* <theme>
|
||||
* <name>High Contrast</name>
|
||||
* </theme>
|
||||
* </content>
|
||||
*/
|
||||
* Access the metadata for the content elements of this package
|
||||
*
|
||||
* In addition to the overall package metadata, this class reads in metadata contained in a
|
||||
* <content> element. Each entry in the content element is an element representing some
|
||||
* type of package content (e.g. add-on, macro, theme, etc.). This class places no restriction
|
||||
* on the types, it is up to client code to place requirements on the metadata included
|
||||
* here.
|
||||
*
|
||||
* For example, themes might be specified:
|
||||
* <content>
|
||||
* <theme>
|
||||
* <name>High Contrast</name>
|
||||
* </theme>
|
||||
* </content>
|
||||
*/
|
||||
std::multimap<std::string, Metadata> content() const;
|
||||
|
||||
/**
|
||||
* Convenience accessor for unrecognized simple metadata.
|
||||
*
|
||||
* If the XML parser encounters tags that it does not recognize, and those tags have
|
||||
* no children, a GenericMetadata object is created. Those objects can be accessed using
|
||||
* operator[], which returns a (potentially empty) vector containing all instances of the
|
||||
* given tag. It cannot be used to *create* a new tag, however. See addGenericMetadata().
|
||||
*/
|
||||
* Convenience accessor for unrecognized simple metadata.
|
||||
*
|
||||
* If the XML parser encounters tags that it does not recognize, and those tags have
|
||||
* no children, a GenericMetadata object is created. Those objects can be accessed using
|
||||
* operator[], which returns a (potentially empty) vector containing all instances of the
|
||||
* given tag. It cannot be used to *create* a new tag, however. See addGenericMetadata().
|
||||
*/
|
||||
std::vector<Meta::GenericMetadata> operator[](const std::string& tag) const;
|
||||
|
||||
/**
|
||||
* Directly access the DOM tree to support unrecognized multi-level metadata
|
||||
*/
|
||||
* Directly access the DOM tree to support unrecognized multi-level metadata
|
||||
*/
|
||||
XERCES_CPP_NAMESPACE::DOMElement* dom() const;
|
||||
|
||||
|
||||
@@ -333,19 +342,19 @@ public:
|
||||
void clearFile();
|
||||
|
||||
/**
|
||||
* Write the metadata to an XML file
|
||||
*/
|
||||
* Write the metadata to an XML file
|
||||
*/
|
||||
void write(const boost::filesystem::path& file) const;
|
||||
|
||||
/**
|
||||
* Determine whether this package satisfies the given dependency
|
||||
*/
|
||||
* Determine whether this package satisfies the given dependency
|
||||
*/
|
||||
bool satisfies(const Meta::Dependency&);
|
||||
|
||||
/**
|
||||
* Determine whether the current metadata specifies support for the currently-running version of FreeCAD.
|
||||
* Does not interrogate content items, which must be queried individually.
|
||||
*/
|
||||
* Determine whether the current metadata specifies support for the currently-running version of
|
||||
* FreeCAD. Does not interrogate content items, which must be queried individually.
|
||||
*/
|
||||
bool supportsCurrentFreeCAD() const;
|
||||
|
||||
private:
|
||||
@@ -384,6 +393,6 @@ private:
|
||||
void appendToElement(XERCES_CPP_NAMESPACE::DOMElement* root) const;
|
||||
};
|
||||
|
||||
}// namespace App
|
||||
} // namespace App
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,7 @@
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <string>
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
#include <App/Document.h>
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
|
||||
#ifndef M_PI
|
||||
# define M_PI 3.14159265358979323846
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
using namespace App;
|
||||
@@ -44,100 +44,116 @@ using namespace App;
|
||||
|
||||
PROPERTY_SOURCE(App::Origin, App::DocumentObject)
|
||||
|
||||
Origin::Origin() : extension(this) {
|
||||
ADD_PROPERTY_TYPE ( OriginFeatures, (nullptr), 0, App::Prop_Hidden,
|
||||
"Axis and baseplanes controlled by the origin" );
|
||||
Origin::Origin()
|
||||
: extension(this)
|
||||
{
|
||||
ADD_PROPERTY_TYPE(OriginFeatures,
|
||||
(nullptr),
|
||||
0,
|
||||
App::Prop_Hidden,
|
||||
"Axis and baseplanes controlled by the origin");
|
||||
|
||||
setStatus(App::NoAutoExpand,true);
|
||||
setStatus(App::NoAutoExpand, true);
|
||||
extension.initExtension(this);
|
||||
}
|
||||
|
||||
|
||||
Origin::~Origin() = default;
|
||||
|
||||
App::OriginFeature *Origin::getOriginFeature( const char *role) const {
|
||||
const auto & features = OriginFeatures.getValues ();
|
||||
auto featIt = std::find_if (features.begin(), features.end(),
|
||||
[role] (App::DocumentObject *obj) {
|
||||
return obj->isDerivedFrom ( App::OriginFeature::getClassTypeId () ) &&
|
||||
strcmp (static_cast<App::OriginFeature *>(obj)->Role.getValue(), role) == 0;
|
||||
} );
|
||||
App::OriginFeature* Origin::getOriginFeature(const char* role) const
|
||||
{
|
||||
const auto& features = OriginFeatures.getValues();
|
||||
auto featIt = std::find_if(features.begin(), features.end(), [role](App::DocumentObject* obj) {
|
||||
return obj->isDerivedFrom(App::OriginFeature::getClassTypeId())
|
||||
&& strcmp(static_cast<App::OriginFeature*>(obj)->Role.getValue(), role) == 0;
|
||||
});
|
||||
if (featIt != features.end()) {
|
||||
return static_cast<App::OriginFeature *>(*featIt);
|
||||
} else {
|
||||
return static_cast<App::OriginFeature*>(*featIt);
|
||||
}
|
||||
else {
|
||||
|
||||
std::stringstream err;
|
||||
err << "Origin \"" << getFullName () << "\" doesn't contain feature with role \""
|
||||
<< role << '"';
|
||||
throw Base::RuntimeError ( err.str().c_str () );
|
||||
err << "Origin \"" << getFullName() << "\" doesn't contain feature with role \"" << role
|
||||
<< '"';
|
||||
throw Base::RuntimeError(err.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
App::Line *Origin::getAxis( const char *role ) const {
|
||||
App::OriginFeature *feat = getOriginFeature (role);
|
||||
if ( feat->isDerivedFrom(App::Line::getClassTypeId () ) ) {
|
||||
return static_cast<App::Line *> (feat);
|
||||
} else {
|
||||
App::Line* Origin::getAxis(const char* role) const
|
||||
{
|
||||
App::OriginFeature* feat = getOriginFeature(role);
|
||||
if (feat->isDerivedFrom(App::Line::getClassTypeId())) {
|
||||
return static_cast<App::Line*>(feat);
|
||||
}
|
||||
else {
|
||||
std::stringstream err;
|
||||
err << "Origin \"" << getFullName () << "\" contains bad Axis object for role \""
|
||||
<< role << '"';
|
||||
throw Base::RuntimeError ( err.str().c_str () );
|
||||
err << "Origin \"" << getFullName() << "\" contains bad Axis object for role \"" << role
|
||||
<< '"';
|
||||
throw Base::RuntimeError(err.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
App::Plane *Origin::getPlane( const char *role ) const {
|
||||
App::OriginFeature *feat = getOriginFeature (role);
|
||||
if ( feat->isDerivedFrom(App::Plane::getClassTypeId () ) ) {
|
||||
return static_cast<App::Plane *> (feat);
|
||||
} else {
|
||||
App::Plane* Origin::getPlane(const char* role) const
|
||||
{
|
||||
App::OriginFeature* feat = getOriginFeature(role);
|
||||
if (feat->isDerivedFrom(App::Plane::getClassTypeId())) {
|
||||
return static_cast<App::Plane*>(feat);
|
||||
}
|
||||
else {
|
||||
std::stringstream err;
|
||||
err << "Origin \"" << getFullName () << "\" contains bad Plane object for role \""
|
||||
<< role << '"';
|
||||
throw Base::RuntimeError ( err.str().c_str () );
|
||||
err << "Origin \"" << getFullName() << "\" contains bad Plane object for role \"" << role
|
||||
<< '"';
|
||||
throw Base::RuntimeError(err.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
bool Origin::hasObject (const DocumentObject *obj) const {
|
||||
const auto & features = OriginFeatures.getValues ();
|
||||
return std::find (features.begin(), features.end(), obj) != features.end ();
|
||||
bool Origin::hasObject(const DocumentObject* obj) const
|
||||
{
|
||||
const auto& features = OriginFeatures.getValues();
|
||||
return std::find(features.begin(), features.end(), obj) != features.end();
|
||||
}
|
||||
|
||||
short Origin::mustExecute() const {
|
||||
if (OriginFeatures.isTouched ()) {
|
||||
short Origin::mustExecute() const
|
||||
{
|
||||
if (OriginFeatures.isTouched()) {
|
||||
return 1;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return DocumentObject::mustExecute();
|
||||
}
|
||||
}
|
||||
|
||||
App::DocumentObjectExecReturn *Origin::execute() {
|
||||
try { // try to find all base axis and planes in the origin
|
||||
for (const char* role: AxisRoles) {
|
||||
App::Line *axis = getAxis (role);
|
||||
App::DocumentObjectExecReturn* Origin::execute()
|
||||
{
|
||||
try { // try to find all base axis and planes in the origin
|
||||
for (const char* role : AxisRoles) {
|
||||
App::Line* axis = getAxis(role);
|
||||
assert(axis);
|
||||
(void)axis;
|
||||
}
|
||||
for (const char* role: PlaneRoles) {
|
||||
App::Plane *plane = getPlane (role);
|
||||
for (const char* role : PlaneRoles) {
|
||||
App::Plane* plane = getPlane(role);
|
||||
assert(plane);
|
||||
(void)plane;
|
||||
}
|
||||
} catch (const Base::Exception &ex) {
|
||||
setError ();
|
||||
return new App::DocumentObjectExecReturn ( ex.what () );
|
||||
}
|
||||
catch (const Base::Exception& ex) {
|
||||
setError();
|
||||
return new App::DocumentObjectExecReturn(ex.what());
|
||||
}
|
||||
|
||||
return DocumentObject::execute ();
|
||||
return DocumentObject::execute();
|
||||
}
|
||||
|
||||
void Origin::setupObject () {
|
||||
const static struct {
|
||||
void Origin::setupObject()
|
||||
{
|
||||
const static struct
|
||||
{
|
||||
const Base::Type type;
|
||||
const char *role;
|
||||
const QString label;
|
||||
const char* role;
|
||||
const QString label;
|
||||
Base::Rotation rot;
|
||||
}
|
||||
setupData [] = {
|
||||
} setupData[] = {
|
||||
// clang-format off
|
||||
{App::Line::getClassTypeId(), AxisRoles[0], tr("X-axis"), Base::Rotation()},
|
||||
{App::Line::getClassTypeId(), AxisRoles[1], tr("Y-axis"), Base::Rotation(Base::Vector3d(1,1,1), M_PI*2/3)},
|
||||
@@ -148,39 +164,40 @@ void Origin::setupObject () {
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
App::Document *doc = getDocument ();
|
||||
App::Document* doc = getDocument();
|
||||
|
||||
std::vector<App::DocumentObject *> links;
|
||||
for (auto data: setupData) {
|
||||
std::string objName = doc->getUniqueObjectName ( data.role );
|
||||
App::DocumentObject *featureObj = doc->addObject ( data.type.getName(), objName.c_str () );
|
||||
std::vector<App::DocumentObject*> links;
|
||||
for (auto data : setupData) {
|
||||
std::string objName = doc->getUniqueObjectName(data.role);
|
||||
App::DocumentObject* featureObj = doc->addObject(data.type.getName(), objName.c_str());
|
||||
|
||||
assert ( featureObj && featureObj->isDerivedFrom ( App::OriginFeature::getClassTypeId () ) );
|
||||
assert(featureObj && featureObj->isDerivedFrom(App::OriginFeature::getClassTypeId()));
|
||||
|
||||
QByteArray byteArray = data.label.toUtf8();
|
||||
QByteArray byteArray = data.label.toUtf8();
|
||||
featureObj->Label.setValue(byteArray.constData());
|
||||
|
||||
App::OriginFeature *feature = static_cast <App::OriginFeature *> ( featureObj );
|
||||
feature->Placement.setValue ( Base::Placement ( Base::Vector3d (), data.rot ) );
|
||||
feature->Role.setValue ( data.role );
|
||||
App::OriginFeature* feature = static_cast<App::OriginFeature*>(featureObj);
|
||||
feature->Placement.setValue(Base::Placement(Base::Vector3d(), data.rot));
|
||||
feature->Role.setValue(data.role);
|
||||
|
||||
links.push_back (feature);
|
||||
links.push_back(feature);
|
||||
}
|
||||
|
||||
OriginFeatures.setValues (links);
|
||||
OriginFeatures.setValues(links);
|
||||
}
|
||||
|
||||
void Origin::unsetupObject () {
|
||||
const auto &objsLnk = OriginFeatures.getValues ();
|
||||
void Origin::unsetupObject()
|
||||
{
|
||||
const auto& objsLnk = OriginFeatures.getValues();
|
||||
// Copy to set to assert we won't call methode more then one time for each object
|
||||
std::set<App::DocumentObject *> objs (objsLnk.begin(), objsLnk.end());
|
||||
std::set<App::DocumentObject*> objs(objsLnk.begin(), objsLnk.end());
|
||||
// Remove all controlled objects
|
||||
for (auto obj: objs ) {
|
||||
for (auto obj : objs) {
|
||||
// Check that previous deletes wasn't inderectly removed one of our objects
|
||||
const auto &objsLnk = OriginFeatures.getValues ();
|
||||
if ( std::find(objsLnk.begin(), objsLnk.end(), obj) != objsLnk.end()) {
|
||||
if ( ! obj->isRemoving() ) {
|
||||
obj->getDocument()->removeObject (obj->getNameInDocument());
|
||||
const auto& objsLnk = OriginFeatures.getValues();
|
||||
if (std::find(objsLnk.begin(), objsLnk.end(), obj) != objsLnk.end()) {
|
||||
if (!obj->isRemoving()) {
|
||||
obj->getDocument()->removeObject(obj->getNameInDocument());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,19 +211,25 @@ Origin::OriginExtension::OriginExtension(Origin* obj)
|
||||
Group.setStatus(Property::Transient, true);
|
||||
}
|
||||
|
||||
void Origin::OriginExtension::initExtension(ExtensionContainer* obj) {
|
||||
void Origin::OriginExtension::initExtension(ExtensionContainer* obj)
|
||||
{
|
||||
App::GroupExtension::initExtension(obj);
|
||||
}
|
||||
|
||||
bool Origin::OriginExtension::extensionGetSubObject(DocumentObject *&ret, const char *subname,
|
||||
PyObject **pyobj, Base::Matrix4D *mat, bool, int depth) const {
|
||||
bool Origin::OriginExtension::extensionGetSubObject(DocumentObject*& ret,
|
||||
const char* subname,
|
||||
PyObject** pyobj,
|
||||
Base::Matrix4D* mat,
|
||||
bool,
|
||||
int depth) const
|
||||
{
|
||||
if (!subname || subname[0] == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// mapping of object name to role name
|
||||
std::string name(subname);
|
||||
for (int i=0; i<3; i++) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (name.rfind(Origin::AxisRoles[i], 0) == 0) {
|
||||
name = Origin::AxisRoles[i];
|
||||
break;
|
||||
@@ -219,14 +242,17 @@ bool Origin::OriginExtension::extensionGetSubObject(DocumentObject *&ret, const
|
||||
|
||||
try {
|
||||
ret = obj->getOriginFeature(name.c_str());
|
||||
if (!ret)
|
||||
if (!ret) {
|
||||
return false;
|
||||
const char *dot = strchr(subname, '.');
|
||||
if (dot)
|
||||
subname = dot+1;
|
||||
else
|
||||
}
|
||||
const char* dot = strchr(subname, '.');
|
||||
if (dot) {
|
||||
subname = dot + 1;
|
||||
}
|
||||
else {
|
||||
subname = "";
|
||||
ret = ret->getSubObject(subname, pyobj, mat, true, depth+1);
|
||||
}
|
||||
ret = ret->getSubObject(subname, pyobj, mat, true, depth + 1);
|
||||
return true;
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace App
|
||||
|
||||
/** Base class of all geometric document objects.
|
||||
*/
|
||||
class AppExport Origin : public App::DocumentObject
|
||||
class AppExport Origin: public App::DocumentObject
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(App::Origin);
|
||||
Q_DECLARE_TR_FUNCTIONS(App::Origin)
|
||||
@@ -46,7 +46,8 @@ public:
|
||||
~Origin() override;
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
const char* getViewProviderName() const override {
|
||||
const char* getViewProviderName() const override
|
||||
{
|
||||
return "Gui::ViewProviderOrigin";
|
||||
}
|
||||
|
||||
@@ -56,58 +57,67 @@ public:
|
||||
*/
|
||||
///@{
|
||||
// returns X axis
|
||||
App::Line *getX () const {
|
||||
return getAxis (AxisRoles[0]);
|
||||
App::Line* getX() const
|
||||
{
|
||||
return getAxis(AxisRoles[0]);
|
||||
}
|
||||
// returns Y axis
|
||||
App::Line *getY () const {
|
||||
return getAxis (AxisRoles[1]);
|
||||
App::Line* getY() const
|
||||
{
|
||||
return getAxis(AxisRoles[1]);
|
||||
}
|
||||
// returns Z axis
|
||||
App::Line *getZ () const {
|
||||
return getAxis (AxisRoles[2]);
|
||||
App::Line* getZ() const
|
||||
{
|
||||
return getAxis(AxisRoles[2]);
|
||||
}
|
||||
|
||||
// returns XY plane
|
||||
App::Plane *getXY () const {
|
||||
return getPlane (PlaneRoles[0]);
|
||||
App::Plane* getXY() const
|
||||
{
|
||||
return getPlane(PlaneRoles[0]);
|
||||
}
|
||||
// returns XZ plane
|
||||
App::Plane *getXZ () const {
|
||||
return getPlane (PlaneRoles[1]);
|
||||
App::Plane* getXZ() const
|
||||
{
|
||||
return getPlane(PlaneRoles[1]);
|
||||
}
|
||||
// returns YZ plane
|
||||
App::Plane *getYZ () const {
|
||||
return getPlane (PlaneRoles[2]);
|
||||
App::Plane* getYZ() const
|
||||
{
|
||||
return getPlane(PlaneRoles[2]);
|
||||
}
|
||||
|
||||
/// Returns all axis objects to iterate on them
|
||||
std::vector<App::Line *> axes() const {
|
||||
return { getX(), getY(), getZ() };
|
||||
std::vector<App::Line*> axes() const
|
||||
{
|
||||
return {getX(), getY(), getZ()};
|
||||
}
|
||||
|
||||
/// Returns all base planes objects to iterate on them
|
||||
std::vector<App::Plane *> planes() const {
|
||||
return { getXY(), getXZ(), getYZ() };
|
||||
std::vector<App::Plane*> planes() const
|
||||
{
|
||||
return {getXY(), getXZ(), getYZ()};
|
||||
}
|
||||
|
||||
/// Returns all controlled objects (both planes and axis) to iterate on them
|
||||
std::vector<App::OriginFeature *> baseObjects() const {
|
||||
return { getX(), getY(), getZ(), getXY(), getXZ(), getYZ() };
|
||||
std::vector<App::OriginFeature*> baseObjects() const
|
||||
{
|
||||
return {getX(), getY(), getZ(), getXY(), getXZ(), getYZ()};
|
||||
}
|
||||
|
||||
/// Returns an axis by it's name
|
||||
App::OriginFeature *getOriginFeature( const char* role ) const;
|
||||
App::OriginFeature* getOriginFeature(const char* role) const;
|
||||
|
||||
/// Returns an axis by it's name
|
||||
App::Line *getAxis( const char* role ) const;
|
||||
App::Line* getAxis(const char* role) const;
|
||||
|
||||
/// Returns an axis by it's name
|
||||
App::Plane *getPlane( const char* role ) const;
|
||||
App::Plane* getPlane(const char* role) const;
|
||||
///@}
|
||||
|
||||
/// Returns true if the given object is part of the origin
|
||||
bool hasObject (const DocumentObject *obj) const;
|
||||
bool hasObject(const DocumentObject* obj) const;
|
||||
|
||||
/// Returns the default bounding box of the origin (use this if you confused what should be s )
|
||||
// TODO Delete me if not really needed (2015-09-01, Fat-Zer)
|
||||
@@ -126,27 +136,33 @@ public:
|
||||
|
||||
protected:
|
||||
/// Checks integrity of the Origin
|
||||
App::DocumentObjectExecReturn *execute() override;
|
||||
App::DocumentObjectExecReturn* execute() override;
|
||||
/// Creates all corresponding Axes and Planes objects for the origin if they aren't linked yet
|
||||
void setupObject () override;
|
||||
void setupObject() override;
|
||||
/// Removes all planes and axis if they are still linked to the document
|
||||
void unsetupObject () override;
|
||||
void unsetupObject() override;
|
||||
|
||||
private:
|
||||
struct SetupData;
|
||||
void setupOriginFeature (App::PropertyLink &featProp, const SetupData &data);
|
||||
void setupOriginFeature(App::PropertyLink& featProp, const SetupData& data);
|
||||
|
||||
class OriginExtension : public GeoFeatureGroupExtension {
|
||||
class OriginExtension: public GeoFeatureGroupExtension
|
||||
{
|
||||
Origin* obj;
|
||||
|
||||
public:
|
||||
explicit OriginExtension(Origin* obj);
|
||||
void initExtension(ExtensionContainer* obj) override;
|
||||
bool extensionGetSubObject(DocumentObject *&ret, const char *subname,
|
||||
PyObject **, Base::Matrix4D *, bool, int) const override;
|
||||
bool extensionGetSubObject(DocumentObject*& ret,
|
||||
const char* subname,
|
||||
PyObject**,
|
||||
Base::Matrix4D*,
|
||||
bool,
|
||||
int) const override;
|
||||
};
|
||||
OriginExtension extension;
|
||||
};
|
||||
|
||||
} //namespace App
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_Origin_H
|
||||
#endif // APP_Origin_H
|
||||
|
||||
@@ -35,7 +35,7 @@ PROPERTY_SOURCE(App::Line, App::OriginFeature)
|
||||
|
||||
OriginFeature::OriginFeature()
|
||||
{
|
||||
ADD_PROPERTY_TYPE ( Role, (""), 0, App::Prop_ReadOnly, "Role of the feature in the Origin" ) ;
|
||||
ADD_PROPERTY_TYPE(Role, (""), 0, App::Prop_ReadOnly, "Role of the feature in the Origin");
|
||||
|
||||
// Set placement to read-only
|
||||
Placement.setStatus(Property::Hidden, true);
|
||||
@@ -43,18 +43,20 @@ OriginFeature::OriginFeature()
|
||||
|
||||
OriginFeature::~OriginFeature() = default;
|
||||
|
||||
Origin * OriginFeature::getOrigin () {
|
||||
App::Document *doc = getDocument();
|
||||
auto origins = doc->getObjectsOfType ( App::Origin::getClassTypeId() );
|
||||
Origin* OriginFeature::getOrigin()
|
||||
{
|
||||
App::Document* doc = getDocument();
|
||||
auto origins = doc->getObjectsOfType(App::Origin::getClassTypeId());
|
||||
|
||||
auto originIt= std::find_if (origins.begin(), origins.end(), [this] (DocumentObject *origin) {
|
||||
assert ( origin->isDerivedFrom ( App::Origin::getClassTypeId() ) );
|
||||
return static_cast<App::Origin *> (origin)->hasObject (this);
|
||||
} );
|
||||
auto originIt = std::find_if(origins.begin(), origins.end(), [this](DocumentObject* origin) {
|
||||
assert(origin->isDerivedFrom(App::Origin::getClassTypeId()));
|
||||
return static_cast<App::Origin*>(origin)->hasObject(this);
|
||||
});
|
||||
if (originIt == origins.end()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
assert ( (*originIt)->isDerivedFrom ( App::Origin::getClassTypeId() ) );
|
||||
return static_cast<App::Origin *> (*originIt);
|
||||
}
|
||||
else {
|
||||
assert((*originIt)->isDerivedFrom(App::Origin::getClassTypeId()));
|
||||
return static_cast<App::Origin*>(*originIt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ class Origin;
|
||||
class AppExport OriginFeature: public App::GeoFeature
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(App::OriginFeature);
|
||||
|
||||
public:
|
||||
/// additional information about the feature usage (e.g. "BasePlane-XY" or "Axis-X" in a Origin)
|
||||
PropertyString Role;
|
||||
@@ -45,25 +46,31 @@ public:
|
||||
~OriginFeature() override;
|
||||
|
||||
/// Finds the origin object this plane belongs to
|
||||
App::Origin *getOrigin ();
|
||||
App::Origin* getOrigin();
|
||||
};
|
||||
|
||||
class AppExport Plane: public App::OriginFeature {
|
||||
class AppExport Plane: public App::OriginFeature
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(App::OriginFeature);
|
||||
|
||||
public:
|
||||
const char* getViewProviderName() const override {
|
||||
const char* getViewProviderName() const override
|
||||
{
|
||||
return "Gui::ViewProviderPlane";
|
||||
}
|
||||
};
|
||||
|
||||
class AppExport Line: public App::OriginFeature {
|
||||
class AppExport Line: public App::OriginFeature
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(App::OriginFeature);
|
||||
|
||||
public:
|
||||
const char* getViewProviderName() const override {
|
||||
const char* getViewProviderName() const override
|
||||
{
|
||||
return "Gui::ViewProviderLine";
|
||||
}
|
||||
};
|
||||
|
||||
} //namespace App
|
||||
} // namespace App
|
||||
|
||||
#endif /* end of include guard: ORIGINFEATURE_H */
|
||||
|
||||
@@ -38,139 +38,172 @@ using namespace App;
|
||||
|
||||
EXTENSION_PROPERTY_SOURCE(App::OriginGroupExtension, App::GeoFeatureGroupExtension)
|
||||
|
||||
OriginGroupExtension::OriginGroupExtension () {
|
||||
OriginGroupExtension::OriginGroupExtension()
|
||||
{
|
||||
|
||||
initExtensionType(OriginGroupExtension::getExtensionClassTypeId());
|
||||
|
||||
EXTENSION_ADD_PROPERTY_TYPE ( Origin, (nullptr), 0, App::Prop_Hidden, "Origin linked to the group" );
|
||||
EXTENSION_ADD_PROPERTY_TYPE(Origin,
|
||||
(nullptr),
|
||||
0,
|
||||
App::Prop_Hidden,
|
||||
"Origin linked to the group");
|
||||
Origin.setScope(LinkScope::Child);
|
||||
}
|
||||
|
||||
OriginGroupExtension::~OriginGroupExtension () = default;
|
||||
OriginGroupExtension::~OriginGroupExtension() = default;
|
||||
|
||||
App::Origin *OriginGroupExtension::getOrigin () const {
|
||||
App::DocumentObject *originObj = Origin.getValue ();
|
||||
App::Origin* OriginGroupExtension::getOrigin() const
|
||||
{
|
||||
App::DocumentObject* originObj = Origin.getValue();
|
||||
|
||||
if ( !originObj ) {
|
||||
if (!originObj) {
|
||||
std::stringstream err;
|
||||
err << "Can't find Origin for \"" << getExtendedObject()->getFullName () << "\"";
|
||||
throw Base::RuntimeError ( err.str().c_str () );
|
||||
|
||||
} else if (! originObj->isDerivedFrom ( App::Origin::getClassTypeId() ) ) {
|
||||
err << "Can't find Origin for \"" << getExtendedObject()->getFullName() << "\"";
|
||||
throw Base::RuntimeError(err.str().c_str());
|
||||
}
|
||||
else if (!originObj->isDerivedFrom(App::Origin::getClassTypeId())) {
|
||||
std::stringstream err;
|
||||
err << "Bad object \"" << originObj->getFullName () << "\"(" << originObj->getTypeId().getName()
|
||||
<< ") linked to the Origin of \"" << getExtendedObject()->getFullName () << "\"";
|
||||
throw Base::RuntimeError ( err.str().c_str () );
|
||||
} else {
|
||||
return static_cast<App::Origin *> ( originObj );
|
||||
err << "Bad object \"" << originObj->getFullName() << "\"("
|
||||
<< originObj->getTypeId().getName() << ") linked to the Origin of \""
|
||||
<< getExtendedObject()->getFullName() << "\"";
|
||||
throw Base::RuntimeError(err.str().c_str());
|
||||
}
|
||||
else {
|
||||
return static_cast<App::Origin*>(originObj);
|
||||
}
|
||||
}
|
||||
|
||||
bool OriginGroupExtension::extensionGetSubObject(DocumentObject *&ret, const char *subname,
|
||||
PyObject **pyObj, Base::Matrix4D *mat, bool transform, int depth) const
|
||||
bool OriginGroupExtension::extensionGetSubObject(DocumentObject*& ret,
|
||||
const char* subname,
|
||||
PyObject** pyObj,
|
||||
Base::Matrix4D* mat,
|
||||
bool transform,
|
||||
int depth) const
|
||||
{
|
||||
App::DocumentObject *originObj = Origin.getValue ();
|
||||
const char *dot;
|
||||
if(originObj && originObj->isAttachedToDocument() &&
|
||||
subname && (dot=strchr(subname,'.')))
|
||||
{
|
||||
App::DocumentObject* originObj = Origin.getValue();
|
||||
const char* dot;
|
||||
if (originObj && originObj->isAttachedToDocument() && subname && (dot = strchr(subname, '.'))) {
|
||||
bool found;
|
||||
if(subname[0] == '$')
|
||||
found = std::string(subname+1,dot)==originObj->Label.getValue();
|
||||
else
|
||||
found = std::string(subname,dot)==originObj->getNameInDocument();
|
||||
if(found) {
|
||||
if(mat && transform)
|
||||
if (subname[0] == '$') {
|
||||
found = std::string(subname + 1, dot) == originObj->Label.getValue();
|
||||
}
|
||||
else {
|
||||
found = std::string(subname, dot) == originObj->getNameInDocument();
|
||||
}
|
||||
if (found) {
|
||||
if (mat && transform) {
|
||||
*mat *= const_cast<OriginGroupExtension*>(this)->placement().getValue().toMatrix();
|
||||
ret = originObj->getSubObject(dot+1,pyObj,mat,true,depth+1);
|
||||
}
|
||||
ret = originObj->getSubObject(dot + 1, pyObj, mat, true, depth + 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return GeoFeatureGroupExtension::extensionGetSubObject(ret,subname,pyObj,mat,transform,depth);
|
||||
return GeoFeatureGroupExtension::extensionGetSubObject(ret,
|
||||
subname,
|
||||
pyObj,
|
||||
mat,
|
||||
transform,
|
||||
depth);
|
||||
}
|
||||
|
||||
App::DocumentObject *OriginGroupExtension::getGroupOfObject (const DocumentObject* obj) {
|
||||
App::DocumentObject* OriginGroupExtension::getGroupOfObject(const DocumentObject* obj)
|
||||
{
|
||||
|
||||
if(!obj)
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool isOriginFeature = obj->isDerivedFrom(App::OriginFeature::getClassTypeId());
|
||||
|
||||
auto list = obj->getInList();
|
||||
for (auto o : list) {
|
||||
if(o->hasExtension(App::OriginGroupExtension::getExtensionClassTypeId()))
|
||||
if (o->hasExtension(App::OriginGroupExtension::getExtensionClassTypeId())) {
|
||||
return o;
|
||||
}
|
||||
else if (isOriginFeature && o->isDerivedFrom(App::Origin::getClassTypeId())) {
|
||||
auto result = getGroupOfObject(o);
|
||||
if(result)
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
short OriginGroupExtension::extensionMustExecute() {
|
||||
if (Origin.isTouched ()) {
|
||||
short OriginGroupExtension::extensionMustExecute()
|
||||
{
|
||||
if (Origin.isTouched()) {
|
||||
return 1;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return GeoFeatureGroupExtension::extensionMustExecute();
|
||||
}
|
||||
}
|
||||
|
||||
App::DocumentObjectExecReturn *OriginGroupExtension::extensionExecute() {
|
||||
try { // try to find all base axis and planes in the origin
|
||||
getOrigin ();
|
||||
} catch (const Base::Exception &ex) {
|
||||
//getExtendedObject()->setError ();
|
||||
return new App::DocumentObjectExecReturn ( ex.what () );
|
||||
App::DocumentObjectExecReturn* OriginGroupExtension::extensionExecute()
|
||||
{
|
||||
try { // try to find all base axis and planes in the origin
|
||||
getOrigin();
|
||||
}
|
||||
catch (const Base::Exception& ex) {
|
||||
// getExtendedObject()->setError ();
|
||||
return new App::DocumentObjectExecReturn(ex.what());
|
||||
}
|
||||
|
||||
return GeoFeatureGroupExtension::extensionExecute ();
|
||||
return GeoFeatureGroupExtension::extensionExecute();
|
||||
}
|
||||
|
||||
App::DocumentObject *OriginGroupExtension::getLocalizedOrigin(App::Document *doc) {
|
||||
App::DocumentObject *originObject = doc->addObject ( "App::Origin", "Origin" );
|
||||
App::DocumentObject* OriginGroupExtension::getLocalizedOrigin(App::Document* doc)
|
||||
{
|
||||
App::DocumentObject* originObject = doc->addObject("App::Origin", "Origin");
|
||||
QByteArray byteArray = tr("Origin").toUtf8();
|
||||
originObject->Label.setValue(byteArray.constData());
|
||||
return originObject;
|
||||
}
|
||||
|
||||
void OriginGroupExtension::onExtendedSetupObject () {
|
||||
App::Document *doc = getExtendedObject()->getDocument ();
|
||||
void OriginGroupExtension::onExtendedSetupObject()
|
||||
{
|
||||
App::Document* doc = getExtendedObject()->getDocument();
|
||||
|
||||
App::DocumentObject *originObj = getLocalizedOrigin(doc);
|
||||
App::DocumentObject* originObj = getLocalizedOrigin(doc);
|
||||
|
||||
assert ( originObj && originObj->isDerivedFrom ( App::Origin::getClassTypeId () ) );
|
||||
Origin.setValue (originObj);
|
||||
assert(originObj && originObj->isDerivedFrom(App::Origin::getClassTypeId()));
|
||||
Origin.setValue(originObj);
|
||||
|
||||
GeoFeatureGroupExtension::onExtendedSetupObject ();
|
||||
GeoFeatureGroupExtension::onExtendedSetupObject();
|
||||
}
|
||||
|
||||
void OriginGroupExtension::onExtendedUnsetupObject () {
|
||||
App::DocumentObject *origin = Origin.getValue ();
|
||||
if (origin && !origin->isRemoving ()) {
|
||||
origin->getDocument ()->removeObject (origin->getNameInDocument());
|
||||
void OriginGroupExtension::onExtendedUnsetupObject()
|
||||
{
|
||||
App::DocumentObject* origin = Origin.getValue();
|
||||
if (origin && !origin->isRemoving()) {
|
||||
origin->getDocument()->removeObject(origin->getNameInDocument());
|
||||
}
|
||||
|
||||
GeoFeatureGroupExtension::onExtendedUnsetupObject ();
|
||||
GeoFeatureGroupExtension::onExtendedUnsetupObject();
|
||||
}
|
||||
|
||||
void OriginGroupExtension::extensionOnChanged(const Property* p) {
|
||||
if(p == &Origin) {
|
||||
App::DocumentObject *owner = getExtendedObject();
|
||||
App::DocumentObject *origin = Origin.getValue();
|
||||
void OriginGroupExtension::extensionOnChanged(const Property* p)
|
||||
{
|
||||
if (p == &Origin) {
|
||||
App::DocumentObject* owner = getExtendedObject();
|
||||
App::DocumentObject* origin = Origin.getValue();
|
||||
// Document::Importing indicates the object is being imported (i.e.
|
||||
// copied). So check the Origin ownership here to prevent copy without
|
||||
// dependency
|
||||
if (origin && owner && owner->getDocument()
|
||||
&& owner->getDocument()->testStatus(Document::Importing)) {
|
||||
&& owner->getDocument()->testStatus(Document::Importing)) {
|
||||
for (auto o : origin->getInList()) {
|
||||
if(o != owner && o->hasExtension(App::OriginGroupExtension::getExtensionClassTypeId())) {
|
||||
App::Document *document = owner->getDocument();
|
||||
// Temporarily reset 'Restoring' status to allow document to auto label new objects
|
||||
Base::ObjectStatusLocker<Document::Status, Document> guard(
|
||||
Document::Restoring, document, false);
|
||||
if (o != owner
|
||||
&& o->hasExtension(App::OriginGroupExtension::getExtensionClassTypeId())) {
|
||||
App::Document* document = owner->getDocument();
|
||||
// Temporarily reset 'Restoring' status to allow document to auto label new
|
||||
// objects
|
||||
Base::ObjectStatusLocker<Document::Status, Document> guard(Document::Restoring,
|
||||
document,
|
||||
false);
|
||||
Origin.setValue(getLocalizedOrigin(document));
|
||||
FC_WARN("Reset origin in " << owner->getFullName());
|
||||
return;
|
||||
@@ -183,83 +216,99 @@ void OriginGroupExtension::extensionOnChanged(const Property* p) {
|
||||
|
||||
void OriginGroupExtension::relinkToOrigin(App::DocumentObject* obj)
|
||||
{
|
||||
//we get all links and replace the origin objects if needed (subnames need not to change, they
|
||||
//would stay the same)
|
||||
std::vector< App::DocumentObject* > result;
|
||||
// we get all links and replace the origin objects if needed (subnames need not to change, they
|
||||
// would stay the same)
|
||||
std::vector<App::DocumentObject*> result;
|
||||
std::vector<App::Property*> list;
|
||||
obj->getPropertyList(list);
|
||||
for(App::Property* prop : list) {
|
||||
if(prop->isDerivedFrom<App::PropertyLink>()) {
|
||||
for (App::Property* prop : list) {
|
||||
if (prop->isDerivedFrom<App::PropertyLink>()) {
|
||||
|
||||
auto p = static_cast<App::PropertyLink*>(prop);
|
||||
if(!p->getValue() || !p->getValue()->isDerivedFrom(App::OriginFeature::getClassTypeId()))
|
||||
if (!p->getValue()
|
||||
|| !p->getValue()->isDerivedFrom(App::OriginFeature::getClassTypeId())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
p->setValue(getOrigin()->getOriginFeature(static_cast<OriginFeature*>(p->getValue())->Role.getValue()));
|
||||
p->setValue(getOrigin()->getOriginFeature(
|
||||
static_cast<OriginFeature*>(p->getValue())->Role.getValue()));
|
||||
}
|
||||
else if(prop->isDerivedFrom<App::PropertyLinkList>()) {
|
||||
else if (prop->isDerivedFrom<App::PropertyLinkList>()) {
|
||||
auto p = static_cast<App::PropertyLinkList*>(prop);
|
||||
auto vec = p->getValues();
|
||||
std::vector<App::DocumentObject*> result;
|
||||
bool changed = false;
|
||||
for(App::DocumentObject* o : vec) {
|
||||
if(!o || !o->isDerivedFrom(App::OriginFeature::getClassTypeId()))
|
||||
for (App::DocumentObject* o : vec) {
|
||||
if (!o || !o->isDerivedFrom(App::OriginFeature::getClassTypeId())) {
|
||||
result.push_back(o);
|
||||
}
|
||||
else {
|
||||
result.push_back(getOrigin()->getOriginFeature(static_cast<OriginFeature*>(o)->Role.getValue()));
|
||||
result.push_back(getOrigin()->getOriginFeature(
|
||||
static_cast<OriginFeature*>(o)->Role.getValue()));
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if(changed)
|
||||
if (changed) {
|
||||
static_cast<App::PropertyLinkList*>(prop)->setValues(result);
|
||||
}
|
||||
}
|
||||
else if(prop->isDerivedFrom<App::PropertyLinkSub>()) {
|
||||
else if (prop->isDerivedFrom<App::PropertyLinkSub>()) {
|
||||
auto p = static_cast<App::PropertyLinkSub*>(prop);
|
||||
if(!p->getValue() || !p->getValue()->isDerivedFrom(App::OriginFeature::getClassTypeId()))
|
||||
if (!p->getValue()
|
||||
|| !p->getValue()->isDerivedFrom(App::OriginFeature::getClassTypeId())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<std::string> subValues = p->getSubValues();
|
||||
p->setValue(getOrigin()->getOriginFeature(static_cast<OriginFeature*>(p->getValue())->Role.getValue()), subValues);
|
||||
p->setValue(getOrigin()->getOriginFeature(
|
||||
static_cast<OriginFeature*>(p->getValue())->Role.getValue()),
|
||||
subValues);
|
||||
}
|
||||
else if(prop->isDerivedFrom<App::PropertyLinkSubList>()) {
|
||||
else if (prop->isDerivedFrom<App::PropertyLinkSubList>()) {
|
||||
auto p = static_cast<App::PropertyLinkSubList*>(prop);
|
||||
auto vec = p->getSubListValues();
|
||||
bool changed = false;
|
||||
for(auto &v : vec) {
|
||||
if(v.first && v.first->isDerivedFrom(App::OriginFeature::getClassTypeId())) {
|
||||
v.first = getOrigin()->getOriginFeature(static_cast<OriginFeature*>(v.first)->Role.getValue());
|
||||
for (auto& v : vec) {
|
||||
if (v.first && v.first->isDerivedFrom(App::OriginFeature::getClassTypeId())) {
|
||||
v.first = getOrigin()->getOriginFeature(
|
||||
static_cast<OriginFeature*>(v.first)->Role.getValue());
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if(changed)
|
||||
if (changed) {
|
||||
p->setSubListValues(vec);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector< DocumentObject* > OriginGroupExtension::addObjects(std::vector<DocumentObject*> objs) {
|
||||
std::vector<DocumentObject*> OriginGroupExtension::addObjects(std::vector<DocumentObject*> objs)
|
||||
{
|
||||
|
||||
for(auto obj : objs)
|
||||
for (auto obj : objs) {
|
||||
relinkToOrigin(obj);
|
||||
}
|
||||
|
||||
return App::GeoFeatureGroupExtension::addObjects(objs);
|
||||
}
|
||||
|
||||
bool OriginGroupExtension::hasObject(const DocumentObject* obj, bool recursive) const {
|
||||
bool OriginGroupExtension::hasObject(const DocumentObject* obj, bool recursive) const
|
||||
{
|
||||
|
||||
if(Origin.getValue() && (obj == getOrigin() || getOrigin()->hasObject(obj)))
|
||||
if (Origin.getValue() && (obj == getOrigin() || getOrigin()->hasObject(obj))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return App::GroupExtension::hasObject(obj, recursive);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Python feature ---------------------------------------------------------
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
EXTENSION_PROPERTY_SOURCE_TEMPLATE(App::OriginGroupExtensionPython, App::OriginGroupExtension)
|
||||
|
||||
// explicit template instantiation
|
||||
template class AppExport ExtensionPythonT<GroupExtensionPythonT<OriginGroupExtension>>;
|
||||
}
|
||||
} // namespace App
|
||||
|
||||
@@ -26,26 +26,28 @@
|
||||
#include "GeoFeatureGroupExtension.h"
|
||||
#include "QCoreApplication"
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
class Origin;
|
||||
|
||||
/**
|
||||
* Represents an abstract placeable group of objects with an associated Origin
|
||||
*/
|
||||
class AppExport OriginGroupExtension : public App::GeoFeatureGroupExtension
|
||||
class AppExport OriginGroupExtension: public App::GeoFeatureGroupExtension
|
||||
{
|
||||
EXTENSION_PROPERTY_HEADER_WITH_OVERRIDE(App::OriginGroupExtension);
|
||||
Q_DECLARE_TR_FUNCTIONS(App::OriginGroupExtension)
|
||||
|
||||
public:
|
||||
OriginGroupExtension ();
|
||||
~OriginGroupExtension () override;
|
||||
OriginGroupExtension();
|
||||
~OriginGroupExtension() override;
|
||||
|
||||
/// Returns the origin link or throws an exception
|
||||
App::Origin *getOrigin () const;
|
||||
App::Origin* getOrigin() const;
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
virtual const char* getViewProviderName () const {
|
||||
virtual const char* getViewProviderName() const
|
||||
{
|
||||
return "Gui::ViewProviderOriginGroup";
|
||||
}
|
||||
|
||||
@@ -54,10 +56,10 @@ public:
|
||||
* In case this object is not part of any geoFeatureGroup, 0 is returned.
|
||||
* @param obj the object to search for
|
||||
*/
|
||||
static DocumentObject* getGroupOfObject (const DocumentObject* obj);
|
||||
static DocumentObject* getGroupOfObject(const DocumentObject* obj);
|
||||
|
||||
/// Returns true on changing OriginFeature set
|
||||
short extensionMustExecute () override;
|
||||
short extensionMustExecute() override;
|
||||
|
||||
/// Origin linked to the group
|
||||
PropertyLink Origin;
|
||||
@@ -68,26 +70,30 @@ public:
|
||||
std::vector<DocumentObject*> addObjects(std::vector<DocumentObject*> obj) override;
|
||||
bool hasObject(const DocumentObject* obj, bool recursive = false) const override;
|
||||
|
||||
bool extensionGetSubObject(DocumentObject *&ret, const char *subname, PyObject **pyObj,
|
||||
Base::Matrix4D *mat, bool transform, int depth) const override;
|
||||
bool extensionGetSubObject(DocumentObject*& ret,
|
||||
const char* subname,
|
||||
PyObject** pyObj,
|
||||
Base::Matrix4D* mat,
|
||||
bool transform,
|
||||
int depth) const override;
|
||||
|
||||
void extensionOnChanged(const Property* p) override;
|
||||
|
||||
protected:
|
||||
/// Checks integrity of the Origin
|
||||
App::DocumentObjectExecReturn *extensionExecute () override;
|
||||
App::DocumentObjectExecReturn* extensionExecute() override;
|
||||
/// Creates the corresponding Origin object
|
||||
void onExtendedSetupObject () override;
|
||||
void onExtendedSetupObject() override;
|
||||
/// Removes all planes and axis if they are still linked to the document
|
||||
void onExtendedUnsetupObject () override;
|
||||
void onExtendedUnsetupObject() override;
|
||||
|
||||
private:
|
||||
/// Creates a localized Origin object
|
||||
App::DocumentObject *getLocalizedOrigin(App::Document *doc);
|
||||
App::DocumentObject* getLocalizedOrigin(App::Document* doc);
|
||||
};
|
||||
|
||||
using OriginGroupExtensionPython = ExtensionPythonT<GroupExtensionPythonT<OriginGroupExtension>>;
|
||||
|
||||
} /* App */
|
||||
} // namespace App
|
||||
|
||||
#endif /* end of include guard: ORIGINGROUP_H_QHTU73IF */
|
||||
|
||||
@@ -16,4 +16,3 @@
|
||||
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ std::string OriginGroupExtensionPy::representation() const
|
||||
return {"<OriginGroup object>"};
|
||||
}
|
||||
|
||||
PyObject *OriginGroupExtensionPy::getCustomAttributes(const char* /*attr*/) const
|
||||
PyObject* OriginGroupExtensionPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
@@ -44,5 +44,3 @@ int OriginGroupExtensionPy::setCustomAttributes(const char* /*attr*/, PyObject*
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ PROPERTY_SOURCE_WITH_EXTENSIONS(App::Part, App::GeoFeature)
|
||||
|
||||
Part::Part()
|
||||
{
|
||||
ADD_PROPERTY(Type,(""));
|
||||
ADD_PROPERTY(Type, (""));
|
||||
ADD_PROPERTY_TYPE(Material, (nullptr), 0, App::Prop_None, "The Material for this Part");
|
||||
ADD_PROPERTY_TYPE(Meta, (), 0, App::Prop_None, "Map with additional meta information");
|
||||
|
||||
@@ -62,22 +62,25 @@ Part::Part()
|
||||
|
||||
Part::~Part() = default;
|
||||
|
||||
static App::Part *_getPartOfObject(const DocumentObject *obj,
|
||||
std::set<const DocumentObject*> *objset)
|
||||
static App::Part* _getPartOfObject(const DocumentObject* obj,
|
||||
std::set<const DocumentObject*>* objset)
|
||||
{
|
||||
// as a Part is a geofeaturegroup it must directly link to all
|
||||
// objects it contains, even if they are in additional groups etc.
|
||||
// But we still must call 'hasObject()' to exclude link brought in by
|
||||
// expressions.
|
||||
for (auto inObj : obj->getInList()) {
|
||||
if (objset && !objset->insert(inObj).second)
|
||||
if (objset && !objset->insert(inObj).second) {
|
||||
continue;
|
||||
}
|
||||
auto group = inObj->getExtensionByType<GeoFeatureGroupExtension>(true);
|
||||
if(group && group->hasObject(obj)) {
|
||||
if(inObj->isDerivedFrom(App::Part::getClassTypeId()))
|
||||
if (group && group->hasObject(obj)) {
|
||||
if (inObj->isDerivedFrom(App::Part::getClassTypeId())) {
|
||||
return static_cast<App::Part*>(inObj);
|
||||
else if (objset)
|
||||
}
|
||||
else if (objset) {
|
||||
return _getPartOfObject(inObj, objset);
|
||||
}
|
||||
// Only one parent geofeature group per object, so break
|
||||
break;
|
||||
}
|
||||
@@ -86,35 +89,41 @@ static App::Part *_getPartOfObject(const DocumentObject *obj,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
App::Part *Part::getPartOfObject (const DocumentObject* obj, bool recursive) {
|
||||
if (!recursive)
|
||||
App::Part* Part::getPartOfObject(const DocumentObject* obj, bool recursive)
|
||||
{
|
||||
if (!recursive) {
|
||||
return _getPartOfObject(obj, nullptr);
|
||||
std::set<const DocumentObject *> objset;
|
||||
}
|
||||
std::set<const DocumentObject*> objset;
|
||||
objset.insert(obj);
|
||||
return _getPartOfObject(obj, &objset);
|
||||
}
|
||||
|
||||
|
||||
PyObject *Part::getPyObject()
|
||||
PyObject* Part::getPyObject()
|
||||
{
|
||||
if (PythonObject.is(Py::_None())){
|
||||
if (PythonObject.is(Py::_None())) {
|
||||
// ref counter is set to 1
|
||||
PythonObject = Py::Object(new PartPy(this),true);
|
||||
PythonObject = Py::Object(new PartPy(this), true);
|
||||
}
|
||||
return Py::new_reference_to(PythonObject);
|
||||
}
|
||||
|
||||
void Part::handleChangedPropertyType(Base::XMLReader &reader, const char *TypeName, App::Property *prop)
|
||||
void Part::handleChangedPropertyType(Base::XMLReader& reader,
|
||||
const char* TypeName,
|
||||
App::Property* prop)
|
||||
{
|
||||
// Migrate Material from App::PropertyMap to App::PropertyLink
|
||||
if (!strcmp(TypeName, "App::PropertyMap")) {
|
||||
App::PropertyMap oldvalue;
|
||||
oldvalue.Restore(reader);
|
||||
if (oldvalue.getSize()) {
|
||||
auto oldprop = static_cast<App::PropertyMap*>(addDynamicProperty("App::PropertyMap", "Material_old", "Base"));
|
||||
auto oldprop = static_cast<App::PropertyMap*>(
|
||||
addDynamicProperty("App::PropertyMap", "Material_old", "Base"));
|
||||
oldprop->setValues(oldvalue.getValues());
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
App::GeoFeature::handleChangedPropertyType(reader, TypeName, prop);
|
||||
}
|
||||
}
|
||||
@@ -124,21 +133,21 @@ void Part::handleChangedPropertyType(Base::XMLReader &reader, const char *TypeNa
|
||||
// Not quite sure yet making Part derivable in Python is good Idea!
|
||||
// JR 2014
|
||||
|
||||
//namespace App {
|
||||
// namespace App {
|
||||
///// @cond DOXERR
|
||||
//PROPERTY_SOURCE_TEMPLATE(App::PartPython, App::Part)
|
||||
//template<> const char* App::PartPython::getViewProviderName(void) const {
|
||||
// return "Gui::ViewProviderPartPython";
|
||||
//}
|
||||
//template<> PyObject* App::PartPython::getPyObject(void) {
|
||||
// if (PythonObject.is(Py::_None())) {
|
||||
// // ref counter is set to 1
|
||||
// PythonObject = Py::Object(new FeaturePythonPyT<App::PartPy>(this),true);
|
||||
// }
|
||||
// return Py::new_reference_to(PythonObject);
|
||||
//}
|
||||
// PROPERTY_SOURCE_TEMPLATE(App::PartPython, App::Part)
|
||||
// template<> const char* App::PartPython::getViewProviderName(void) const {
|
||||
// return "Gui::ViewProviderPartPython";
|
||||
// }
|
||||
// template<> PyObject* App::PartPython::getPyObject(void) {
|
||||
// if (PythonObject.is(Py::_None())) {
|
||||
// // ref counter is set to 1
|
||||
// PythonObject = Py::Object(new FeaturePythonPyT<App::PartPy>(this),true);
|
||||
// }
|
||||
// return Py::new_reference_to(PythonObject);
|
||||
// }
|
||||
///// @endcond
|
||||
//
|
||||
//// explicit template instantiation
|
||||
//template class AppExport FeaturePythonT<App::Part>;
|
||||
//}
|
||||
// template class AppExport FeaturePythonT<App::Part>;
|
||||
// }
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace App
|
||||
|
||||
/** Base class of all geometric document objects.
|
||||
*/
|
||||
class AppExport Part : public App::GeoFeature, public App::OriginGroupExtension
|
||||
class AppExport Part: public App::GeoFeature, public App::OriginGroupExtension
|
||||
{
|
||||
PROPERTY_HEADER_WITH_EXTENSIONS(App::Part);
|
||||
|
||||
@@ -44,26 +44,26 @@ public:
|
||||
PropertyString Type;
|
||||
|
||||
/** @name base properties of all Assembly Items
|
||||
* These properties correspond mostly to the meta information
|
||||
* in the App::Document class
|
||||
*/
|
||||
* These properties correspond mostly to the meta information
|
||||
* in the App::Document class
|
||||
*/
|
||||
//@{
|
||||
/// Id e.g. Part number
|
||||
App::PropertyString Id;
|
||||
App::PropertyString Id;
|
||||
/// unique identifier of the Item
|
||||
App::PropertyUUID Uid;
|
||||
App::PropertyUUID Uid;
|
||||
/// material descriptions
|
||||
App::PropertyLink Material;
|
||||
App::PropertyLink Material;
|
||||
/// Meta descriptions
|
||||
App::PropertyMap Meta;
|
||||
App::PropertyMap Meta;
|
||||
|
||||
/** License string
|
||||
* Holds the short license string for the Item, e.g. CC-BY
|
||||
* for the Creative Commons license suit.
|
||||
*/
|
||||
App::PropertyString License;
|
||||
* Holds the short license string for the Item, e.g. CC-BY
|
||||
* for the Creative Commons license suit.
|
||||
*/
|
||||
App::PropertyString License;
|
||||
/// License description/contract URL
|
||||
App::PropertyString LicenseURL;
|
||||
App::PropertyString LicenseURL;
|
||||
//@}
|
||||
|
||||
/** @name Visual properties */
|
||||
@@ -80,12 +80,15 @@ public:
|
||||
~Part() override;
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
const char* getViewProviderName() const override {
|
||||
const char* getViewProviderName() const override
|
||||
{
|
||||
return "Gui::ViewProviderPart";
|
||||
}
|
||||
|
||||
|
||||
void handleChangedPropertyType(Base::XMLReader &reader, const char *TypeName, App::Property *prop) override;
|
||||
void handleChangedPropertyType(Base::XMLReader& reader,
|
||||
const char* TypeName,
|
||||
App::Property* prop) override;
|
||||
|
||||
/**
|
||||
* Returns the part which contains this object.
|
||||
@@ -93,14 +96,14 @@ public:
|
||||
* @param obj the object to search for
|
||||
* @param recursive: whether to recursively find any grand parent Part container
|
||||
*/
|
||||
static App::Part* getPartOfObject (const DocumentObject* obj, bool recursive=true);
|
||||
static App::Part* getPartOfObject(const DocumentObject* obj, bool recursive = true);
|
||||
|
||||
PyObject *getPyObject() override;
|
||||
PyObject* getPyObject() override;
|
||||
};
|
||||
|
||||
//using PartPython = App::FeaturePythonT<Part>;
|
||||
// using PartPython = App::FeaturePythonT<Part>;
|
||||
|
||||
} //namespace App
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // APP_Part_H
|
||||
#endif // APP_Part_H
|
||||
|
||||
@@ -35,7 +35,7 @@ std::string PartPy::representation() const
|
||||
return {"<Part object>"};
|
||||
}
|
||||
|
||||
PyObject *PartPy::getCustomAttributes(const char* /*attr*/) const
|
||||
PyObject* PartPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
@@ -44,4 +44,3 @@ int PartPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
using namespace App;
|
||||
|
||||
|
||||
Path::Path(const std::vector<Base::Persistence *> &PathVector)
|
||||
: _PathVector(PathVector)
|
||||
{
|
||||
}
|
||||
Path::Path(const std::vector<Base::Persistence*>& PathVector)
|
||||
: _PathVector(PathVector)
|
||||
{}
|
||||
|
||||
@@ -36,21 +36,22 @@ namespace App
|
||||
class AppExport Path
|
||||
{
|
||||
protected:
|
||||
std::vector<Base::Persistence *> _PathVector;
|
||||
std::vector<Base::Persistence*> _PathVector;
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
Path() = default;
|
||||
explicit Path(const std::vector<Base::Persistence *> & PathVector);
|
||||
explicit Path(const std::vector<Base::Persistence*>& PathVector);
|
||||
|
||||
virtual ~Path() = default;
|
||||
|
||||
const std::vector<Base::Persistence *> & getVector() const {
|
||||
const std::vector<Base::Persistence*>& getVector() const
|
||||
{
|
||||
return _PathVector;
|
||||
}
|
||||
};
|
||||
|
||||
} //namespace App
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // APP_Path_H
|
||||
#endif // APP_Path_H
|
||||
|
||||
@@ -42,16 +42,14 @@ Placement::Placement() = default;
|
||||
Placement::~Placement() = default;
|
||||
|
||||
|
||||
|
||||
// Python feature ---------------------------------------------------------
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
PROPERTY_SOURCE_TEMPLATE(App::PlacementPython, App::Placement)
|
||||
template<> const char* App::PlacementPython::getViewProviderName() const {
|
||||
return "Gui::ViewProviderPlacementPython";
|
||||
template<>
|
||||
const char* App::PlacementPython::getViewProviderName() const
|
||||
{
|
||||
return "Gui::ViewProviderPlacementPython";
|
||||
}
|
||||
template class AppExport FeaturePythonT<App::Placement>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace App
|
||||
|
||||
@@ -37,21 +37,20 @@ class AppExport Placement: public App::GeoFeature
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(App::Placement);
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
Placement();
|
||||
~Placement() override;
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
const char* getViewProviderName() const override {
|
||||
return "Gui::ViewProviderPlacement";
|
||||
}
|
||||
|
||||
/// Constructor
|
||||
Placement();
|
||||
~Placement() override;
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
const char* getViewProviderName() const override
|
||||
{
|
||||
return "Gui::ViewProviderPlacement";
|
||||
}
|
||||
};
|
||||
using PlacementPython = App::FeaturePythonT<App::Placement>;
|
||||
|
||||
|
||||
} //namespace App
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,4 +22,3 @@
|
||||
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
|
||||
@@ -27,12 +27,13 @@
|
||||
|
||||
// point at which warnings of overly long specifiers disabled
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( disable : 4251 )
|
||||
#pragma warning( disable : 4273 )
|
||||
#pragma warning( disable : 4275 )
|
||||
#pragma warning( disable : 4482 ) // nonstandard extension used: enum 'App::ObjectStatus' used in qualified name
|
||||
#pragma warning( disable : 4503 )
|
||||
#pragma warning( disable : 4786 ) // specifier longer then 255 chars
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4273)
|
||||
#pragma warning(disable : 4275)
|
||||
#pragma warning(disable : 4482) // nonstandard extension used: enum 'App::ObjectStatus' used in
|
||||
// qualified name
|
||||
#pragma warning(disable : 4503)
|
||||
#pragma warning(disable : 4786) // specifier longer then 255 chars
|
||||
#endif
|
||||
|
||||
#ifdef FC_OS_WIN32
|
||||
@@ -52,15 +53,15 @@
|
||||
#include <cfloat>
|
||||
|
||||
#ifdef FC_OS_WIN32
|
||||
# include <crtdbg.h>
|
||||
# include <direct.h>
|
||||
# include <windows.h>
|
||||
#include <crtdbg.h>
|
||||
#include <direct.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(FC_OS_LINUX) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
||||
# include <pwd.h>
|
||||
# include <unistd.h>
|
||||
# include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
// Streams
|
||||
@@ -100,6 +101,6 @@
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#endif //_PreComp_
|
||||
#endif //_PreComp_
|
||||
|
||||
#endif // APP_PRECOMPILED_H
|
||||
#endif // APP_PRECOMPILED_H
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Library General Public License (LGPL) *
|
||||
* as published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* for detail see the LICENCE text file. *
|
||||
* *
|
||||
* FreeCAD is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with FreeCAD; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Library General Public License (LGPL) *
|
||||
* as published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* for detail see the LICENCE text file. *
|
||||
* *
|
||||
* FreeCAD is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with FreeCAD; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef PROGRAMOPTIONSUTILITIES_H
|
||||
#define PROGRAMOPTIONSUTILITIES_H
|
||||
@@ -28,12 +28,13 @@
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
namespace App::Util{
|
||||
namespace App::Util
|
||||
{
|
||||
|
||||
std::pair<std::string, std::string> customSyntax(std::string_view strIn)
|
||||
{
|
||||
if(strIn.size() < 2) {
|
||||
return{};
|
||||
if (strIn.size() < 2) {
|
||||
return {};
|
||||
}
|
||||
|
||||
char leadChr {strIn[0]};
|
||||
@@ -53,7 +54,7 @@ std::pair<std::string, std::string> customSyntax(std::string_view strIn)
|
||||
}
|
||||
#endif
|
||||
|
||||
if(rest == "widgetcount"){
|
||||
if (rest == "widgetcount") {
|
||||
return {rest, ""};
|
||||
}
|
||||
|
||||
@@ -73,11 +74,11 @@ std::pair<std::string, std::string> customSyntax(std::string_view strIn)
|
||||
"title",
|
||||
"visual"};
|
||||
|
||||
if(std::find(knowns.begin(), knowns.end(), rest) != knowns.end()) {
|
||||
if (std::find(knowns.begin(), knowns.end(), rest) != knowns.end()) {
|
||||
return {rest, "null"};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif// PROGRAMOPTIONSUTILITIES_H
|
||||
} // namespace App::Util
|
||||
#endif // PROGRAMOPTIONSUTILITIES_H
|
||||
|
||||
@@ -64,12 +64,13 @@ XERCES_CPP_NAMESPACE_USE
|
||||
#endif
|
||||
using namespace App;
|
||||
|
||||
namespace {
|
||||
namespace
|
||||
{
|
||||
class DocumentMetadata
|
||||
{
|
||||
public:
|
||||
explicit DocumentMetadata(XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* xmlDocument)
|
||||
: xmlDocument{xmlDocument}
|
||||
: xmlDocument {xmlDocument}
|
||||
{}
|
||||
|
||||
ProjectFile::Metadata getMetadata() const
|
||||
@@ -103,11 +104,13 @@ public:
|
||||
private:
|
||||
void readProgramVersion()
|
||||
{
|
||||
if (DOMNodeList* nodes = xmlDocument->getElementsByTagName(XStr("Document").unicodeForm())) {
|
||||
if (DOMNodeList* nodes =
|
||||
xmlDocument->getElementsByTagName(XStr("Document").unicodeForm())) {
|
||||
for (XMLSize_t i = 0; i < nodes->getLength(); i++) {
|
||||
DOMNode* node = nodes->item(i);
|
||||
if (node->getNodeType() == DOMNode::ELEMENT_NODE) {
|
||||
DOMNode* nameAttr = node->getAttributes()->getNamedItem(XStr("ProgramVersion").unicodeForm());
|
||||
DOMNode* nameAttr =
|
||||
node->getAttributes()->getNamedItem(XStr("ProgramVersion").unicodeForm());
|
||||
if (nameAttr) {
|
||||
std::string value = StrX(nameAttr->getNodeValue()).c_str();
|
||||
metadata.programVersion = value;
|
||||
@@ -163,12 +166,14 @@ private:
|
||||
static std::string readValue(DOMNode* node)
|
||||
{
|
||||
if (node->getNodeType() == DOMNode::ELEMENT_NODE) {
|
||||
if (DOMElement* child = static_cast<DOMElement*>(node)->getFirstElementChild()) { // NOLINT
|
||||
if (DOMNode* nameAttr = child->getAttributes()->getNamedItem(XStr("value").unicodeForm())) {
|
||||
std::string value = StrX(nameAttr->getNodeValue()).c_str();
|
||||
return value;
|
||||
}
|
||||
}
|
||||
if (DOMElement* child =
|
||||
static_cast<DOMElement*>(node)->getFirstElementChild()) { // NOLINT
|
||||
if (DOMNode* nameAttr =
|
||||
child->getAttributes()->getNamedItem(XStr("value").unicodeForm())) {
|
||||
std::string value = StrX(nameAttr->getNodeValue()).c_str();
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
@@ -178,7 +183,7 @@ private:
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* xmlDocument;
|
||||
ProjectFile::Metadata metadata;
|
||||
};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ProjectFile::ProjectFile()
|
||||
: xmlDocument(nullptr)
|
||||
@@ -259,8 +264,8 @@ std::list<ProjectFile::Object> ProjectFile::getObjects() const
|
||||
for (XMLSize_t i = 0; i < nodes->getLength(); i++) {
|
||||
DOMNode* node = nodes->item(i);
|
||||
if (node->getNodeType() == DOMNode::ELEMENT_NODE) {
|
||||
DOMNodeList* objectList =
|
||||
static_cast<DOMElement*>(node)->getElementsByTagName(XStr("Object").unicodeForm()); // NOLINT
|
||||
DOMNodeList* objectList = static_cast<DOMElement*>(node)->getElementsByTagName(
|
||||
XStr("Object").unicodeForm()); // NOLINT
|
||||
for (XMLSize_t j = 0; j < objectList->getLength(); j++) {
|
||||
DOMNode* objectNode = objectList->item(j);
|
||||
DOMNode* typeAttr =
|
||||
@@ -291,8 +296,8 @@ std::list<std::string> ProjectFile::getObjectsOfType(const Base::Type& typeId) c
|
||||
for (XMLSize_t i = 0; i < nodes->getLength(); i++) {
|
||||
DOMNode* node = nodes->item(i);
|
||||
if (node->getNodeType() == DOMNode::ELEMENT_NODE) {
|
||||
DOMNodeList* objectList =
|
||||
static_cast<DOMElement*>(node)->getElementsByTagName(XStr("Object").unicodeForm()); // NOLINT
|
||||
DOMNodeList* objectList = static_cast<DOMElement*>(node)->getElementsByTagName(
|
||||
XStr("Object").unicodeForm()); // NOLINT
|
||||
for (XMLSize_t j = 0; j < objectList->getLength(); j++) {
|
||||
DOMNode* objectNode = objectList->item(j);
|
||||
DOMNode* typeAttr =
|
||||
@@ -311,9 +316,7 @@ std::list<std::string> ProjectFile::getObjectsOfType(const Base::Type& typeId) c
|
||||
return names;
|
||||
}
|
||||
|
||||
bool ProjectFile::restoreObject(const std::string& name,
|
||||
App::PropertyContainer* obj,
|
||||
bool verbose)
|
||||
bool ProjectFile::restoreObject(const std::string& name, App::PropertyContainer* obj, bool verbose)
|
||||
{
|
||||
Base::FileInfo fi(stdFile);
|
||||
Base::ifstream file(fi, std::ios::in | std::ios::binary);
|
||||
@@ -367,8 +370,8 @@ Base::Type ProjectFile::getTypeId(const std::string& name) const
|
||||
for (XMLSize_t i = 0; i < nodes->getLength(); i++) {
|
||||
DOMNode* node = nodes->item(i);
|
||||
if (node->getNodeType() == DOMNode::ELEMENT_NODE) {
|
||||
DOMNodeList* objectList =
|
||||
static_cast<DOMElement*>(node)->getElementsByTagName(XStr("Object").unicodeForm()); // NOLINT
|
||||
DOMNodeList* objectList = static_cast<DOMElement*>(node)->getElementsByTagName(
|
||||
XStr("Object").unicodeForm()); // NOLINT
|
||||
for (XMLSize_t j = 0; j < objectList->getLength(); j++) {
|
||||
DOMNode* objectNode = objectList->item(j);
|
||||
DOMNode* typeAttr =
|
||||
@@ -388,8 +391,7 @@ Base::Type ProjectFile::getTypeId(const std::string& name) const
|
||||
return Base::Type::badType();
|
||||
}
|
||||
|
||||
std::list<ProjectFile::PropertyFile>
|
||||
ProjectFile::getPropertyFiles(const std::string& name) const
|
||||
std::list<ProjectFile::PropertyFile> ProjectFile::getPropertyFiles(const std::string& name) const
|
||||
{
|
||||
// <ObjectData Count="1">
|
||||
// <Object name="Mesh">
|
||||
@@ -409,8 +411,8 @@ ProjectFile::getPropertyFiles(const std::string& name) const
|
||||
for (XMLSize_t i = 0; i < nodes->getLength(); i++) {
|
||||
DOMNode* node = nodes->item(i);
|
||||
if (node->getNodeType() == DOMNode::ELEMENT_NODE) {
|
||||
DOMNodeList* objectList =
|
||||
static_cast<DOMElement*>(node)->getElementsByTagName(XStr("Object").unicodeForm()); // NOLINT
|
||||
DOMNodeList* objectList = static_cast<DOMElement*>(node)->getElementsByTagName(
|
||||
XStr("Object").unicodeForm()); // NOLINT
|
||||
for (XMLSize_t j = 0; j < objectList->getLength(); j++) {
|
||||
DOMNode* objectNode = objectList->item(j);
|
||||
DOMNode* nameAttr =
|
||||
@@ -488,8 +490,8 @@ std::list<std::string> ProjectFile::getInputFiles(const std::string& name) const
|
||||
for (XMLSize_t i = 0; i < nodes->getLength(); i++) {
|
||||
DOMNode* node = nodes->item(i);
|
||||
if (node->getNodeType() == DOMNode::ELEMENT_NODE) {
|
||||
DOMNodeList* objectList =
|
||||
static_cast<DOMElement*>(node)->getElementsByTagName(XStr("Object").unicodeForm()); // NOLINT
|
||||
DOMNodeList* objectList = static_cast<DOMElement*>(node)->getElementsByTagName(
|
||||
XStr("Object").unicodeForm()); // NOLINT
|
||||
for (XMLSize_t j = 0; j < objectList->getLength(); j++) {
|
||||
DOMNode* objectNode = objectList->item(j);
|
||||
DOMNode* nameAttr =
|
||||
@@ -646,8 +648,7 @@ std::string ProjectFile::replaceInputFiles(const std::map<std::string, std::istr
|
||||
return fn;
|
||||
}
|
||||
|
||||
std::string
|
||||
ProjectFile::replacePropertyFiles(const std::map<std::string, App::Property*>& props)
|
||||
std::string ProjectFile::replacePropertyFiles(const std::map<std::string, App::Property*>& props)
|
||||
{
|
||||
// create a new zip file with the name '<zipfile>.<uuid>'
|
||||
std::string uuid = Base::Uuid::createUuid();
|
||||
|
||||
@@ -35,7 +35,12 @@
|
||||
#ifndef XERCES_CPP_NAMESPACE_BEGIN
|
||||
#define XERCES_CPP_NAMESPACE_QUALIFIER
|
||||
using namespace XERCES_CPP_NAMESPACE;
|
||||
namespace XERCES_CPP_NAMESPACE { class DOMNode; class DOMElement; class DOMDocument; }
|
||||
namespace XERCES_CPP_NAMESPACE
|
||||
{
|
||||
class DOMNode;
|
||||
class DOMElement;
|
||||
class DOMDocument;
|
||||
} // namespace XERCES_CPP_NAMESPACE
|
||||
#else
|
||||
XERCES_CPP_NAMESPACE_BEGIN
|
||||
class DOMDocument;
|
||||
@@ -210,6 +215,6 @@ private:
|
||||
};
|
||||
|
||||
|
||||
} // namespace APP
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_PROJECTFILE_H
|
||||
|
||||
@@ -40,7 +40,8 @@ using namespace App;
|
||||
const int App::CellAddress::MAX_ROWS = 16384;
|
||||
const int App::CellAddress::MAX_COLUMNS = 26 * 26 + 26;
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
// From a given cell address the '$' must be at within the first
|
||||
// few characters
|
||||
bool maybeAbsolute(std::string_view address)
|
||||
@@ -50,9 +51,9 @@ bool maybeAbsolute(std::string_view address)
|
||||
address = address.substr(0, MAX_COLUMNS_LETTERS + 1);
|
||||
return address.find("$") != std::string_view::npos;
|
||||
}
|
||||
}
|
||||
} // namespace App
|
||||
|
||||
Range::Range(const char * range, bool normalize)
|
||||
Range::Range(const char* range, bool normalize)
|
||||
{
|
||||
std::string from;
|
||||
std::string to;
|
||||
@@ -97,7 +98,7 @@ Range::Range(int _row_begin, int _col_begin, int _row_end, int _col_end, bool no
|
||||
col_curr = col_begin;
|
||||
}
|
||||
|
||||
Range::Range(const CellAddress &from, const CellAddress &to, bool normalize)
|
||||
Range::Range(const CellAddress& from, const CellAddress& to, bool normalize)
|
||||
: row_begin(from.row())
|
||||
, col_begin(from.col())
|
||||
, row_end(to.row())
|
||||
@@ -128,8 +129,9 @@ bool Range::next()
|
||||
return true;
|
||||
}
|
||||
if (col_curr < col_end) {
|
||||
if (row_curr == row_end + 1)
|
||||
if (row_curr == row_end + 1) {
|
||||
return false;
|
||||
}
|
||||
row_curr = row_begin;
|
||||
++col_curr;
|
||||
return true;
|
||||
@@ -138,14 +140,14 @@ bool Range::next()
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decode a row specification into a 0-based integer.
|
||||
*
|
||||
* @param rowstr Row specified as a string, with "1" being the first row.
|
||||
*
|
||||
* @returns The row.
|
||||
*/
|
||||
* @brief Decode a row specification into a 0-based integer.
|
||||
*
|
||||
* @param rowstr Row specified as a string, with "1" being the first row.
|
||||
*
|
||||
* @returns The row.
|
||||
*/
|
||||
|
||||
int App::decodeRow(const std::string &rowstr, bool silent)
|
||||
int App::decodeRow(const std::string& rowstr, bool silent)
|
||||
{
|
||||
int row = validRow(rowstr);
|
||||
|
||||
@@ -159,10 +161,11 @@ int App::decodeRow(const std::string &rowstr, bool silent)
|
||||
/**
|
||||
* Assumes well-formed input. A through ZZZ. 0-based output
|
||||
*/
|
||||
int columnStringToNum(const std::string &colstr) {
|
||||
int columnStringToNum(const std::string& colstr)
|
||||
{
|
||||
double out {0};
|
||||
int pos {0};
|
||||
for (auto chr = colstr.crbegin(); chr != colstr.crend(); chr++){
|
||||
for (auto chr = colstr.crbegin(); chr != colstr.crend(); chr++) {
|
||||
out += (*chr - 'A' + 1) * std::pow(26, pos++);
|
||||
}
|
||||
|
||||
@@ -170,15 +173,15 @@ int columnStringToNum(const std::string &colstr) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decode a column name string into a 0-based integer.
|
||||
*
|
||||
* @param colstr input string.
|
||||
*
|
||||
* @returns The column.
|
||||
*
|
||||
*/
|
||||
* @brief Decode a column name string into a 0-based integer.
|
||||
*
|
||||
* @param colstr input string.
|
||||
*
|
||||
* @returns The column.
|
||||
*
|
||||
*/
|
||||
|
||||
int App::decodeColumn( const std::string &colstr, bool silent )
|
||||
int App::decodeColumn(const std::string& colstr, bool silent)
|
||||
{
|
||||
if (validColumn(colstr)) {
|
||||
return columnStringToNum(colstr);
|
||||
@@ -192,19 +195,19 @@ int App::decodeColumn( const std::string &colstr, bool silent )
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determine whether a row specification is valid or not.
|
||||
*
|
||||
* @param rowstr Row specified as a string, with "1" being the first row.
|
||||
*
|
||||
* @returns 0 or positive on success, -1 on error.
|
||||
*/
|
||||
* @brief Determine whether a row specification is valid or not.
|
||||
*
|
||||
* @param rowstr Row specified as a string, with "1" being the first row.
|
||||
*
|
||||
* @returns 0 or positive on success, -1 on error.
|
||||
*/
|
||||
|
||||
int App::validRow(const std::string &rowstr)
|
||||
int App::validRow(const std::string& rowstr)
|
||||
{
|
||||
char * end;
|
||||
char* end;
|
||||
int i = strtol(rowstr.c_str(), &end, 10);
|
||||
|
||||
if (i <=0 || i > CellAddress::MAX_ROWS || *end) {
|
||||
if (i <= 0 || i > CellAddress::MAX_ROWS || *end) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -212,30 +215,30 @@ int App::validRow(const std::string &rowstr)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determine if a string is a valid column specification.
|
||||
*
|
||||
* @param colstr input string.
|
||||
*
|
||||
* @returns true if valid, false if not.
|
||||
*
|
||||
*/
|
||||
* @brief Determine if a string is a valid column specification.
|
||||
*
|
||||
* @param colstr input string.
|
||||
*
|
||||
* @returns true if valid, false if not.
|
||||
*
|
||||
*/
|
||||
|
||||
bool App::validColumn( const std::string &colstr )
|
||||
bool App::validColumn(const std::string& colstr)
|
||||
{
|
||||
return boost::regex_match(colstr, boost::regex("[A-Z]{1,3}"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a string address into integer \a row and \a column.
|
||||
* row and col are 0-based.
|
||||
*
|
||||
* This function will throw an exception if the specified \a address is invalid.
|
||||
*
|
||||
* @param strAddress Address to parse.
|
||||
*
|
||||
*/
|
||||
* @brief Convert a string address into integer \a row and \a column.
|
||||
* row and col are 0-based.
|
||||
*
|
||||
* This function will throw an exception if the specified \a address is invalid.
|
||||
*
|
||||
* @param strAddress Address to parse.
|
||||
*
|
||||
*/
|
||||
|
||||
App::CellAddress App::stringToAddress(const char * strAddress, bool silent)
|
||||
App::CellAddress App::stringToAddress(const char* strAddress, bool silent)
|
||||
{
|
||||
assert(strAddress);
|
||||
|
||||
@@ -243,24 +246,24 @@ App::CellAddress App::stringToAddress(const char * strAddress, bool silent)
|
||||
boost::cmatch cm;
|
||||
|
||||
if (boost::regex_match(strAddress, cm, e)) {
|
||||
bool absCol = (cm[1].first[0]=='$');
|
||||
std::string r,c;
|
||||
bool absCol = (cm[1].first[0] == '$');
|
||||
std::string r, c;
|
||||
if (absCol) {
|
||||
c = std::string(cm[1].first+1,cm[1].second);
|
||||
c = std::string(cm[1].first + 1, cm[1].second);
|
||||
}
|
||||
else {
|
||||
c = std::string(cm[1].first,cm[1].second);
|
||||
c = std::string(cm[1].first, cm[1].second);
|
||||
}
|
||||
|
||||
bool absRow = (cm[2].first[0]=='$');
|
||||
bool absRow = (cm[2].first[0] == '$');
|
||||
if (absRow) {
|
||||
r = std::string(cm[2].first+1,cm[2].second);
|
||||
r = std::string(cm[2].first + 1, cm[2].second);
|
||||
}
|
||||
else {
|
||||
r = std::string(cm[2].first,cm[2].second);
|
||||
r = std::string(cm[2].first, cm[2].second);
|
||||
}
|
||||
|
||||
return CellAddress(decodeRow(r,silent), decodeColumn(c,silent), absRow, absCol);
|
||||
return CellAddress(decodeRow(r, silent), decodeColumn(c, silent), absRow, absCol);
|
||||
}
|
||||
else if (silent) {
|
||||
return CellAddress();
|
||||
@@ -270,10 +273,10 @@ App::CellAddress App::stringToAddress(const char * strAddress, bool silent)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert given \a cell address into its string representation.
|
||||
*
|
||||
* @returns Address given as a string.
|
||||
*/
|
||||
* @brief Convert given \a cell address into its string representation.
|
||||
*
|
||||
* @returns Address given as a string.
|
||||
*/
|
||||
|
||||
std::string App::CellAddress::toString(Cell cell) const
|
||||
{
|
||||
@@ -311,7 +314,8 @@ std::string App::CellAddress::toString(Cell cell) const
|
||||
* If the passed string is a valid and absolute cell address it will be assigned to this instance.
|
||||
* \return True if it's an absolute cell address and false otherwise
|
||||
*/
|
||||
bool App::CellAddress::parseAbsoluteAddress(const char *address) {
|
||||
bool App::CellAddress::parseAbsoluteAddress(const char* address)
|
||||
{
|
||||
if (maybeAbsolute(address)) {
|
||||
CellAddress addr = stringToAddress(address, true);
|
||||
if (addr.isValid()) {
|
||||
@@ -321,4 +325,3 @@ bool App::CellAddress::parseAbsoluteAddress(const char *address) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
216
src/App/Range.h
216
src/App/Range.h
@@ -29,19 +29,22 @@
|
||||
#include <FCGlobal.h>
|
||||
#endif
|
||||
|
||||
namespace App {
|
||||
namespace App
|
||||
{
|
||||
|
||||
struct CellAddress;
|
||||
|
||||
AppExport CellAddress stringToAddress(const char *strAddress, bool silent=false);
|
||||
AppExport int decodeColumn(const std::string &colstr, bool silent=false);
|
||||
AppExport int decodeRow(const std::string &rowstr, bool silent=false);
|
||||
AppExport bool validColumn(const std::string &colstr);
|
||||
AppExport int validRow(const std::string &rowstr);
|
||||
AppExport CellAddress stringToAddress(const char* strAddress, bool silent = false);
|
||||
AppExport int decodeColumn(const std::string& colstr, bool silent = false);
|
||||
AppExport int decodeRow(const std::string& rowstr, bool silent = false);
|
||||
AppExport bool validColumn(const std::string& colstr);
|
||||
AppExport int validRow(const std::string& rowstr);
|
||||
|
||||
struct AppExport CellAddress {
|
||||
struct AppExport CellAddress
|
||||
{
|
||||
// See call of ENABLE_BITMASK_OPERATORS
|
||||
enum class Cell {
|
||||
enum class Cell
|
||||
{
|
||||
Absolute = 1,
|
||||
ShowRow = 2,
|
||||
ShowColumn = 4,
|
||||
@@ -49,41 +52,79 @@ struct AppExport CellAddress {
|
||||
ShowFull = Absolute | ShowRow | ShowColumn
|
||||
};
|
||||
|
||||
explicit CellAddress(int row = -1, int col = -1, bool absRow=false, bool absCol=false)
|
||||
: _row(row), _col(col), _absRow(absRow), _absCol(absCol)
|
||||
{ }
|
||||
explicit CellAddress(int row = -1, int col = -1, bool absRow = false, bool absCol = false)
|
||||
: _row(row)
|
||||
, _col(col)
|
||||
, _absRow(absRow)
|
||||
, _absCol(absCol)
|
||||
{}
|
||||
|
||||
explicit CellAddress(const char * address) {
|
||||
explicit CellAddress(const char* address)
|
||||
{
|
||||
*this = stringToAddress(address);
|
||||
}
|
||||
|
||||
explicit CellAddress(const std::string & address) {
|
||||
explicit CellAddress(const std::string& address)
|
||||
{
|
||||
*this = stringToAddress(address.c_str());
|
||||
}
|
||||
|
||||
bool parseAbsoluteAddress(const char *txt);
|
||||
bool parseAbsoluteAddress(const char* txt);
|
||||
|
||||
inline int row() const { return _row; }
|
||||
inline int row() const
|
||||
{
|
||||
return _row;
|
||||
}
|
||||
|
||||
inline int col() const { return _col; }
|
||||
inline int col() const
|
||||
{
|
||||
return _col;
|
||||
}
|
||||
|
||||
void setRow(int r, bool clip=false) { _row = (clip && r>=MAX_ROWS) ? MAX_ROWS-1 : r; }
|
||||
void setRow(int r, bool clip = false)
|
||||
{
|
||||
_row = (clip && r >= MAX_ROWS) ? MAX_ROWS - 1 : r;
|
||||
}
|
||||
|
||||
void setCol(int c, bool clip=false) { _col = (clip && c>=MAX_COLUMNS) ? MAX_COLUMNS-1 : c; }
|
||||
void setCol(int c, bool clip = false)
|
||||
{
|
||||
_col = (clip && c >= MAX_COLUMNS) ? MAX_COLUMNS - 1 : c;
|
||||
}
|
||||
|
||||
inline bool operator<(const CellAddress & other) const { return asInt() < other.asInt(); }
|
||||
inline bool operator<(const CellAddress& other) const
|
||||
{
|
||||
return asInt() < other.asInt();
|
||||
}
|
||||
|
||||
inline bool operator>(const CellAddress & other) const { return asInt() > other.asInt(); }
|
||||
inline bool operator>(const CellAddress& other) const
|
||||
{
|
||||
return asInt() > other.asInt();
|
||||
}
|
||||
|
||||
inline bool operator==(const CellAddress & other) const { return asInt() == other.asInt(); }
|
||||
inline bool operator==(const CellAddress& other) const
|
||||
{
|
||||
return asInt() == other.asInt();
|
||||
}
|
||||
|
||||
inline bool operator!=(const CellAddress & other) const { return asInt() != other.asInt(); }
|
||||
inline bool operator!=(const CellAddress& other) const
|
||||
{
|
||||
return asInt() != other.asInt();
|
||||
}
|
||||
|
||||
inline bool isValid() { return (row() >=0 && row() < MAX_ROWS && col() >= 0 && col() < MAX_COLUMNS); }
|
||||
inline bool isValid()
|
||||
{
|
||||
return (row() >= 0 && row() < MAX_ROWS && col() >= 0 && col() < MAX_COLUMNS);
|
||||
}
|
||||
|
||||
inline bool isAbsoluteRow() const { return _absRow; }
|
||||
inline bool isAbsoluteRow() const
|
||||
{
|
||||
return _absRow;
|
||||
}
|
||||
|
||||
inline bool isAbsoluteCol() const { return _absCol; }
|
||||
inline bool isAbsoluteCol() const
|
||||
{
|
||||
return _absCol;
|
||||
}
|
||||
|
||||
std::string toString(Cell = Cell::ShowFull) const;
|
||||
|
||||
@@ -94,8 +135,10 @@ struct AppExport CellAddress {
|
||||
static const int MAX_COLUMNS;
|
||||
|
||||
protected:
|
||||
|
||||
inline unsigned int asInt() const { return ((_row << 16) | _col); }
|
||||
inline unsigned int asInt() const
|
||||
{
|
||||
return ((_row << 16) | _col);
|
||||
}
|
||||
|
||||
short _row;
|
||||
short _col;
|
||||
@@ -115,13 +158,14 @@ protected:
|
||||
*
|
||||
*/
|
||||
|
||||
class AppExport Range {
|
||||
class AppExport Range
|
||||
{
|
||||
public:
|
||||
explicit Range(const char *range, bool normalize=false);
|
||||
explicit Range(const char* range, bool normalize = false);
|
||||
|
||||
Range(int _row_begin, int _col_begin, int _row_end, int _col_end, bool normalize=false);
|
||||
Range(int _row_begin, int _col_begin, int _row_end, int _col_end, bool normalize = false);
|
||||
|
||||
Range(const CellAddress & from, const CellAddress & to, bool normalize=false);
|
||||
Range(const CellAddress& from, const CellAddress& to, bool normalize = false);
|
||||
|
||||
bool next();
|
||||
|
||||
@@ -129,49 +173,87 @@ public:
|
||||
void normalize();
|
||||
|
||||
/** Current row */
|
||||
inline int row() const { return row_curr; }
|
||||
|
||||
/** Current column */
|
||||
inline int column() const { return col_curr; }
|
||||
|
||||
/** Row count */
|
||||
inline int rowCount() const { return row_end - row_begin + 1; }
|
||||
|
||||
/** Column count */
|
||||
inline int colCount() const { return col_end - col_begin + 1; }
|
||||
|
||||
/** Position of start of range */
|
||||
inline CellAddress from() const { return CellAddress(row_begin, col_begin); }
|
||||
|
||||
/** Position of end of range */
|
||||
inline CellAddress to() const { return CellAddress(row_end, col_end); }
|
||||
|
||||
/** Start of range as a string */
|
||||
inline std::string fromCellString() const { return CellAddress(row_begin, col_begin).toString(); }
|
||||
|
||||
/** End of range as a string */
|
||||
inline std::string toCellString() const { return CellAddress(row_end, col_end).toString(); }
|
||||
|
||||
/** Current cell as a string */
|
||||
inline std::string address() const { return CellAddress(row_curr, col_curr).toString(); }
|
||||
|
||||
/** The raneg as a string */
|
||||
inline std::string rangeString() const {
|
||||
return CellAddress(row_begin, col_begin).toString() + ":" + CellAddress(row_end, col_end).toString();
|
||||
inline int row() const
|
||||
{
|
||||
return row_curr;
|
||||
}
|
||||
|
||||
CellAddress operator*() const { return CellAddress(row_curr, col_curr); }
|
||||
/** Current column */
|
||||
inline int column() const
|
||||
{
|
||||
return col_curr;
|
||||
}
|
||||
|
||||
inline bool operator<(const Range & other) const {
|
||||
if(from() < other.from())
|
||||
/** Row count */
|
||||
inline int rowCount() const
|
||||
{
|
||||
return row_end - row_begin + 1;
|
||||
}
|
||||
|
||||
/** Column count */
|
||||
inline int colCount() const
|
||||
{
|
||||
return col_end - col_begin + 1;
|
||||
}
|
||||
|
||||
/** Position of start of range */
|
||||
inline CellAddress from() const
|
||||
{
|
||||
return CellAddress(row_begin, col_begin);
|
||||
}
|
||||
|
||||
/** Position of end of range */
|
||||
inline CellAddress to() const
|
||||
{
|
||||
return CellAddress(row_end, col_end);
|
||||
}
|
||||
|
||||
/** Start of range as a string */
|
||||
inline std::string fromCellString() const
|
||||
{
|
||||
return CellAddress(row_begin, col_begin).toString();
|
||||
}
|
||||
|
||||
/** End of range as a string */
|
||||
inline std::string toCellString() const
|
||||
{
|
||||
return CellAddress(row_end, col_end).toString();
|
||||
}
|
||||
|
||||
/** Current cell as a string */
|
||||
inline std::string address() const
|
||||
{
|
||||
return CellAddress(row_curr, col_curr).toString();
|
||||
}
|
||||
|
||||
/** The raneg as a string */
|
||||
inline std::string rangeString() const
|
||||
{
|
||||
return CellAddress(row_begin, col_begin).toString() + ":"
|
||||
+ CellAddress(row_end, col_end).toString();
|
||||
}
|
||||
|
||||
CellAddress operator*() const
|
||||
{
|
||||
return CellAddress(row_curr, col_curr);
|
||||
}
|
||||
|
||||
inline bool operator<(const Range& other) const
|
||||
{
|
||||
if (from() < other.from()) {
|
||||
return true;
|
||||
if(from() > other.from())
|
||||
}
|
||||
if (from() > other.from()) {
|
||||
return false;
|
||||
}
|
||||
return to() < other.to();
|
||||
}
|
||||
|
||||
/** Number of elements in range */
|
||||
inline int size() const { return (row_end - row_begin + 1) * (col_end - col_begin + 1); }
|
||||
inline int size() const
|
||||
{
|
||||
return (row_end - row_begin + 1) * (col_end - col_begin + 1);
|
||||
}
|
||||
|
||||
private:
|
||||
int row_curr, col_curr;
|
||||
@@ -179,8 +261,8 @@ private:
|
||||
int row_end, col_end;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace App
|
||||
|
||||
ENABLE_BITMASK_OPERATORS(App::CellAddress::Cell)
|
||||
|
||||
#endif // RANGE_H
|
||||
#endif // RANGE_H
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<location filename="../../Link.cpp" line="118"/>
|
||||
<source>Stores the last user choice of whether to apply CopyOnChange setup to all links
|
||||
that reference the same configurable object</source>
|
||||
<translation>Pamti posljednji izbor korisnika o tome treba li primijeniti postavljanje CopyOnChange
|
||||
<translation>Pamti posljednji izbor korisnika o tome treba li primijeniti postavljanje CopyOnChange
|
||||
na sve veze koje referenciraju isti konfigurabilni objekt</translation>
|
||||
</message>
|
||||
</context>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user