Skip to content

Commit

Permalink
Implement and test extension events
Browse files Browse the repository at this point in the history
  • Loading branch information
ickby authored and wwmayer committed Feb 13, 2020
1 parent 9960b67 commit 52c64d8
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 2 deletions.
13 changes: 13 additions & 0 deletions src/App/Application.h
Expand Up @@ -48,6 +48,7 @@ class DocumentObject;
class ApplicationObserver;
class Property;
class AutoTransaction;
class ExtensionContainer;

enum GetLinkOption {
/// Get all links (both directly and in directly) linked to the given object
Expand Down Expand Up @@ -261,6 +262,18 @@ class AppExport Application
/// signal on about changing the editor mode of a property
boost::signals2::signal<void (const App::Document&, const App::Property&)> signalChangePropertyEditor;
//@}

/** @name Signals of extension changes
* These signals are emitted on dynamic extension addition. Dynamic extensions are the ones added by python (c++ ones are part
* of the class definition, hence not dynamic)
* The extension in question is provided as parameter.
*/
//@{
/// signal before adding the extension
boost::signals2::signal<void (const App::ExtensionContainer&, std::string extension)> signalBeforeAddingDynamicExtension;
/// signal after the extension was added
boost::signals2::signal<void (const App::ExtensionContainer&, std::string extension)> signalAddedDynamicExtension;
//@}


/** @name methods for parameter handling */
Expand Down
33 changes: 33 additions & 0 deletions src/App/DocumentObserverPython.cpp
Expand Up @@ -111,6 +111,8 @@ DocumentObserverPython::DocumentObserverPython(const Py::Object& obj) : inst(obj
FC_PY_ELEMENT_ARG1(AppendDynamicProperty, AppendDynamicProperty)
FC_PY_ELEMENT_ARG1(RemoveDynamicProperty, RemoveDynamicProperty)
FC_PY_ELEMENT_ARG2(ChangePropertyEditor, ChangePropertyEditor)
FC_PY_ELEMENT_ARG2(BeforeAddingDynamicExtension, BeforeAddingDynamicExtension)
FC_PY_ELEMENT_ARG2(AddedDynamicExtension, AddedDynamicExtension)
}

DocumentObserverPython::~DocumentObserverPython()
Expand Down Expand Up @@ -541,3 +543,34 @@ void DocumentObserverPython::slotFinishSaveDocument(const App::Document& doc, co
e.ReportException();
}
}

void DocumentObserverPython::slotBeforeAddingDynamicExtension(const App::ExtensionContainer& extcont, std::string extension)
{
Base::PyGILStateLocker lock;
try {
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::ExtensionContainer&>(extcont).getPyObject()));
args.setItem(1, Py::String(extension));
Base::pyCall(pyBeforeAddingDynamicExtension.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
}
}

void DocumentObserverPython::slotAddedDynamicExtension(const App::ExtensionContainer& extcont, std::string extension)
{
Base::PyGILStateLocker lock;
try {
Py::Tuple args(2);
args.setItem(0, Py::Object(const_cast<App::ExtensionContainer&>(extcont).getPyObject()));
args.setItem(1, Py::String(extension));
Base::pyCall(pyAddedDynamicExtension.ptr(),args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
e.ReportException();
}
}

9 changes: 9 additions & 0 deletions src/App/DocumentObserverPython.h
Expand Up @@ -28,6 +28,8 @@

#include <boost/signals2.hpp>
#include <boost/bind.hpp>
#include <string>


namespace App
{
Expand Down Expand Up @@ -105,6 +107,11 @@ class AppExport DocumentObserverPython
void slotStartSaveDocument(const App::Document&, const std::string&);
/** Called when an document has been saved*/
void slotFinishSaveDocument(const App::Document&, const std::string&);
/** Called before an object gets a new extension added*/
void slotBeforeAddingDynamicExtension(const App::ExtensionContainer&, std::string extension);
/** Called when an object gets a dynamic extension added*/
void slotAddedDynamicExtension(const App::ExtensionContainer&, std::string extension);


private:
Py::Object inst;
Expand Down Expand Up @@ -145,6 +152,8 @@ class AppExport DocumentObserverPython
Connection pyAppendDynamicProperty;
Connection pyRemoveDynamicProperty;
Connection pyChangePropertyEditor;
Connection pyBeforeAddingDynamicExtension;
Connection pyAddedDynamicExtension;
};

} //namespace App
Expand Down
8 changes: 6 additions & 2 deletions src/App/ExtensionContainerPyImp.cpp
Expand Up @@ -207,7 +207,7 @@ PyObject* ExtensionContainerPy::addExtension(PyObject *args) {
str << "No extension found of type '" << typeId << "'" << std::ends;
throw Py::Exception(Base::BaseExceptionFreeCADError,str.str());
}

//register the extension
App::Extension* ext = static_cast<App::Extension*>(extension.createInstance());
//check if this really is a python extension!
Expand All @@ -217,7 +217,8 @@ PyObject* ExtensionContainerPy::addExtension(PyObject *args) {
str << "Extension is not a python addable version: '" << typeId << "'" << std::ends;
throw Py::Exception(Base::BaseExceptionFreeCADError,str.str());
}


GetApplication().signalBeforeAddingDynamicExtension(*getExtensionContainerPtr(), typeId);
ext->initExtension(getExtensionContainerPtr());

//set the proxy to allow python overrides
Expand Down Expand Up @@ -260,6 +261,9 @@ PyObject* ExtensionContainerPy::addExtension(PyObject *args) {
}

Py_DECREF(obj);

//throw the appropriate event
GetApplication().signalAddedDynamicExtension(*getExtensionContainerPtr(), typeId);

Py_Return;
}
34 changes: 34 additions & 0 deletions src/Mod/Test/Document.py
Expand Up @@ -1504,6 +1504,16 @@ def slotFinishSaveDocument(self, obj, name):
self.signal.append('DocFinishSave')
self.parameter.append(obj)
self.parameter2.append(name)

def slotBeforeAddingDynamicExtension(self, obj, extension):
self.signal.append('ObjBeforeDynExt')
self.parameter.append(obj)
self.parameter2.append(extension)

def slotAddedDynamicExtension(self, obj, extension):
self.signal.append('ObjDynExt')
self.parameter.append(obj)
self.parameter2.append(extension)

class GuiObserver():

Expand Down Expand Up @@ -1777,6 +1787,18 @@ def testObject(self):
self.failUnless(self.Obs.parameter2.pop() == 'Prop')
self.failUnless(not self.Obs.signal and not self.Obs.parameter and not self.Obs.parameter2)

pyobj.addExtension("App::GroupExtensionPython", None)
self.failUnless(self.Obs.signal.pop() == 'ObjDynExt')
self.failUnless(self.Obs.parameter.pop() is pyobj)
self.failUnless(self.Obs.parameter2.pop() == 'App::GroupExtensionPython')
self.failUnless(self.Obs.signal.pop(0) == 'ObjBeforeDynExt')
self.failUnless(self.Obs.parameter.pop(0) is pyobj)
self.failUnless(self.Obs.parameter2.pop(0) == 'App::GroupExtensionPython')
#a proxy property was changed, hence those events are also in the signal list
self.Obs.signal = []
self.Obs.parameter = []
self.Obs.parameter2 = []

FreeCAD.closeDocument(self.Doc1.Name)
self.Obs.signal = []
self.Obs.parameter = []
Expand Down Expand Up @@ -1907,6 +1929,18 @@ def testGuiObserver(self):
self.failUnless(self.GuiObs.parameter.pop(0) is obj.ViewObject)
self.failUnless(not self.GuiObs.signal and not self.GuiObs.parameter and not self.GuiObs.parameter2)

obj.ViewObject.addExtension("Gui::ViewProviderGroupExtensionPython", None)
self.failUnless(self.Obs.signal.pop() == 'ObjDynExt')
self.failUnless(self.Obs.parameter.pop() is obj.ViewObject)
self.failUnless(self.Obs.parameter2.pop() == 'Gui::ViewProviderGroupExtensionPython')
self.failUnless(self.Obs.signal.pop() == 'ObjBeforeDynExt')
self.failUnless(self.Obs.parameter.pop() is obj.ViewObject)
self.failUnless(self.Obs.parameter2.pop() == 'Gui::ViewProviderGroupExtensionPython')
#a proxy property was changed, hence those events are also in the signal list (but of GUI observer)
self.GuiObs.signal = []
self.GuiObs.parameter = []
self.GuiObs.parameter2 = []

vo = obj.ViewObject
FreeCAD.ActiveDocument.removeObject(obj.Name)
self.failUnless(self.Obs.signal.pop(0) == 'ObjDeleted')
Expand Down

0 comments on commit 52c64d8

Please sign in to comment.