Expose document property changes to python document observer
This commit is contained in:
@@ -416,6 +416,8 @@ Document* Application::newDocument(const char * Name, const char * UserName)
|
||||
|
||||
|
||||
// connect the signals to the application for the new document
|
||||
_pActiveDoc->signalBeforeChange.connect(boost::bind(&App::Application::slotBeforeChangeDoc, this, _1, _2));
|
||||
_pActiveDoc->signalChanged.connect(boost::bind(&App::Application::slotChangedDoc, this, _1, _2));
|
||||
_pActiveDoc->signalNewObject.connect(boost::bind(&App::Application::slotNewObject, this, _1));
|
||||
_pActiveDoc->signalDeletedObject.connect(boost::bind(&App::Application::slotDeletedObject, this, _1));
|
||||
_pActiveDoc->signalBeforeChangeObject.connect(boost::bind(&App::Application::slotBeforeChangeObject, this, _1, _2));
|
||||
@@ -978,6 +980,16 @@ std::map<std::string, std::string> Application::getExportFilters(void) const
|
||||
|
||||
//**************************************************************************
|
||||
// signaling
|
||||
void Application::slotBeforeChangeDoc(const App::Document& doc, const Property& prop)
|
||||
{
|
||||
this->signalBeforeChangeDoc(doc, prop);
|
||||
}
|
||||
|
||||
void Application::slotChangedDoc(const App::Document& doc, const Property& prop)
|
||||
{
|
||||
this->signalChangedDoc(doc, prop);
|
||||
}
|
||||
|
||||
void Application::slotNewObject(const App::DocumentObject&O)
|
||||
{
|
||||
this->signalNewObject(O);
|
||||
|
||||
@@ -128,6 +128,10 @@ public:
|
||||
* the signal of a special document connect to the document itself
|
||||
*/
|
||||
//@{
|
||||
/// signal before change of doc property
|
||||
boost::signal<void (const App::Document&, const App::Property&)> signalBeforeChangeDoc;
|
||||
/// signal on changed doc proeprty
|
||||
boost::signal<void (const App::Document&, const App::Property&)> signalChangedDoc;
|
||||
/// signal on new Object
|
||||
boost::signal<void (const App::DocumentObject&)> signalNewObject;
|
||||
//boost::signal<void (const App::DocumentObject&)> m_sig;
|
||||
@@ -276,6 +280,8 @@ protected:
|
||||
* This slot get connected to all App::Documents created
|
||||
*/
|
||||
//@{
|
||||
void slotBeforeChangeDoc(const App::Document&, const App::Property&);
|
||||
void slotChangedDoc(const App::Document&, const App::Property&);
|
||||
void slotNewObject(const App::DocumentObject&);
|
||||
void slotDeletedObject(const App::DocumentObject&);
|
||||
void slotBeforeChangeObject(const App::DocumentObject&, const App::Property& Prop);
|
||||
|
||||
@@ -1098,8 +1098,15 @@ unsigned int Document::getMaxUndoStackSize(void)const
|
||||
return d->UndoMaxStackSize;
|
||||
}
|
||||
|
||||
void Document::onBeforeChange(const Property* prop) {
|
||||
|
||||
signalBeforeChange(*this, *prop);
|
||||
}
|
||||
|
||||
void Document::onChanged(const Property* prop)
|
||||
{
|
||||
signalChanged(*this, *prop);
|
||||
|
||||
// the Name property is a label for display purposes
|
||||
if (prop == &Label) {
|
||||
App::GetApplication().signalRelabelDocument(*this);
|
||||
|
||||
@@ -112,6 +112,10 @@ public:
|
||||
|
||||
/** @name Signals of the document */
|
||||
//@{
|
||||
/// signal before changing an doc property
|
||||
boost::signal<void (const App::Document&, const App::Property&)> signalBeforeChange;
|
||||
/// signal on changed doc property
|
||||
boost::signal<void (const App::Document&, const App::Property&)> signalChanged;
|
||||
/// signal on new Object
|
||||
boost::signal<void (const App::DocumentObject&)> signalNewObject;
|
||||
//boost::signal<void (const App::DocumentObject&)> m_sig;
|
||||
@@ -375,6 +379,7 @@ protected:
|
||||
void writeObjects(const std::vector<App::DocumentObject*>&, Base::Writer &writer) const;
|
||||
bool saveToFile(const char* filename) const;
|
||||
|
||||
void onBeforeChange(const Property* prop);
|
||||
void onChanged(const Property* prop);
|
||||
/// callback from the Document objects before property will be changed
|
||||
void onBeforeChangeProperty(const TransactionalObject *Who, const Property *What);
|
||||
|
||||
@@ -72,6 +72,10 @@ DocumentObserverPython::DocumentObserverPython(const Py::Object& obj) : inst(obj
|
||||
this->connectApplicationRedoDocument = App::GetApplication().signalRedoDocument.connect(boost::bind
|
||||
(&DocumentObserverPython::slotRedoDocument, this, _1));
|
||||
|
||||
this->connectDocumentBeforeChange = App::GetApplication().signalBeforeChangeDoc.connect(boost::bind
|
||||
(&DocumentObserverPython::slotBeforeChangeDocument, this, _1, _2));
|
||||
this->connectDocumentChanged = App::GetApplication().signalChangedDoc.connect(boost::bind
|
||||
(&DocumentObserverPython::slotChangedDocument, this, _1, _2));
|
||||
this->connectDocumentCreatedObject = App::GetApplication().signalNewObject.connect(boost::bind
|
||||
(&DocumentObserverPython::slotCreatedObject, this, _1));
|
||||
this->connectDocumentDeletedObject = App::GetApplication().signalDeletedObject.connect(boost::bind
|
||||
@@ -103,6 +107,8 @@ DocumentObserverPython::~DocumentObserverPython()
|
||||
this->connectApplicationUndoDocument.disconnect();
|
||||
this->connectApplicationRedoDocument.disconnect();
|
||||
|
||||
this->connectDocumentBeforeChange.disconnect();
|
||||
this->connectDocumentChanged.disconnect();
|
||||
this->connectDocumentCreatedObject.disconnect();
|
||||
this->connectDocumentDeletedObject.disconnect();
|
||||
this->connectDocumentBeforeChangeObject.disconnect();
|
||||
@@ -216,6 +222,52 @@ void DocumentObserverPython::slotRedoDocument(const App::Document& Doc)
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentObserverPython::slotBeforeChangeDocument(const App::Document& Doc, const App::Property& Prop)
|
||||
{
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
if (this->inst.hasAttr(std::string("slotBeforeChangeDocument"))) {
|
||||
Py::Callable method(this->inst.getAttr(std::string("slotBeforeChangeDocument")));
|
||||
Py::Tuple args(2);
|
||||
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
|
||||
// If a property is touched but not part of a document object then its name is null.
|
||||
// In this case the slot function must not be called.
|
||||
const char* prop_name = Doc.getPropertyName(&Prop);
|
||||
if (prop_name) {
|
||||
args.setItem(1, Py::String(prop_name));
|
||||
method.apply(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentObserverPython::slotChangedDocument(const App::Document& Doc, const App::Property& Prop)
|
||||
{
|
||||
Base::PyGILStateLocker lock;
|
||||
try {
|
||||
if (this->inst.hasAttr(std::string("slotChangedDocument"))) {
|
||||
Py::Callable method(this->inst.getAttr(std::string("slotChangedDocument")));
|
||||
Py::Tuple args(2);
|
||||
args.setItem(0, Py::Object(const_cast<App::Document&>(Doc).getPyObject(), true));
|
||||
// If a property is touched but not part of a document object then its name is null.
|
||||
// In this case the slot function must not be called.
|
||||
const char* prop_name = Doc.getPropertyName(&Prop);
|
||||
if (prop_name) {
|
||||
args.setItem(1, Py::String(prop_name));
|
||||
method.apply(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentObserverPython::slotCreatedObject(const App::DocumentObject& Obj)
|
||||
{
|
||||
Base::PyGILStateLocker lock;
|
||||
|
||||
@@ -59,6 +59,10 @@ private:
|
||||
void slotRelabelDocument(const App::Document& Doc);
|
||||
/** Checks if the given document is activated */
|
||||
void slotActivateDocument(const App::Document& Doc);
|
||||
/** The property of an observed document has changed */
|
||||
void slotBeforeChangeDocument(const App::Document& Obj, const App::Property& Prop);
|
||||
/** The property of an observed document has changed */
|
||||
void slotChangedDocument(const App::Document& Obj, const App::Property& Prop);
|
||||
/** Checks if a new object was added. */
|
||||
void slotCreatedObject(const App::DocumentObject& Obj);
|
||||
/** Checks if the given object is about to be removed. */
|
||||
@@ -93,6 +97,8 @@ private:
|
||||
Connection connectApplicationActivateDocument;
|
||||
Connection connectApplicationUndoDocument;
|
||||
Connection connectApplicationRedoDocument;
|
||||
Connection connectDocumentBeforeChange;
|
||||
Connection connectDocumentChanged;
|
||||
Connection connectDocumentCreatedObject;
|
||||
Connection connectDocumentDeletedObject;
|
||||
Connection connectDocumentBeforeChangeObject;
|
||||
|
||||
@@ -1359,6 +1359,16 @@ class DocumentObserverCases(unittest.TestCase):
|
||||
def slotAbortTransaction(self, doc):
|
||||
self.signal.append('DocAbortTransaction');
|
||||
self.parameter = doc;
|
||||
|
||||
def slotBeforeChangeDocument(self, doc, prop):
|
||||
self.signal.append('DocBeforeChange')
|
||||
self.parameter = doc
|
||||
self.parameter2 = prop
|
||||
|
||||
def slotChangedDocument(self, doc, prop):
|
||||
self.signal.append('DocChanged')
|
||||
self.parameter = doc
|
||||
self.parameter2 = prop
|
||||
|
||||
def slotCreatedObject(self, obj):
|
||||
self.signal.append('ObjCreated');
|
||||
@@ -1393,6 +1403,8 @@ class DocumentObserverCases(unittest.TestCase):
|
||||
self.Doc1 = FreeCAD.newDocument("Observer1");
|
||||
self.failUnless(self.Obs.signal.pop(0) == 'DocActivated')
|
||||
self.failUnless(self.Obs.signal.pop(0) == 'DocCreated')
|
||||
self.failUnless(self.Obs.signal.pop(0) == 'DocBeforeChange')
|
||||
self.failUnless(self.Obs.signal.pop(0) == 'DocChanged')
|
||||
self.failUnless(self.Obs.signal.pop(0) == 'DocRelabled')
|
||||
self.failUnless(self.Obs.parameter is self.Doc1)
|
||||
self.failUnless(not self.Obs.signal)
|
||||
@@ -1400,6 +1412,8 @@ class DocumentObserverCases(unittest.TestCase):
|
||||
self.Doc2 = FreeCAD.newDocument("Observer2");
|
||||
self.failUnless(self.Obs.signal.pop(0) == 'DocActivated')
|
||||
self.failUnless(self.Obs.signal.pop(0) == 'DocCreated')
|
||||
self.failUnless(self.Obs.signal.pop(0) == 'DocBeforeChange')
|
||||
self.failUnless(self.Obs.signal.pop(0) == 'DocChanged')
|
||||
self.failUnless(self.Obs.signal.pop(0) == 'DocRelabled')
|
||||
self.failUnless(self.Obs.parameter is self.Doc2)
|
||||
self.failUnless(not self.Obs.signal)
|
||||
@@ -1440,6 +1454,12 @@ class DocumentObserverCases(unittest.TestCase):
|
||||
self.failUnless(self.Obs.parameter is self.Doc2)
|
||||
self.failUnless(not self.Obs.signal)
|
||||
|
||||
self.Doc1.Comment = 'test comment'
|
||||
self.failUnless(self.Obs.signal.pop(0) == 'DocBeforeChange')
|
||||
self.failUnless(self.Obs.signal.pop(0) == 'DocChanged')
|
||||
self.failUnless(self.Obs.parameter is self.Doc1)
|
||||
self.failUnless(self.Obs.parameter2 == 'Comment')
|
||||
|
||||
FreeCAD.closeDocument('Observer2')
|
||||
self.failUnless(self.Obs.signal.pop() == 'DocDeleted')
|
||||
self.failUnless(self.Obs.parameter is self.Doc2)
|
||||
|
||||
Reference in New Issue
Block a user