From bf4dd7920e0d1789b95418185b5c7b123bece5c3 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 8 Oct 2018 14:03:00 +0200 Subject: [PATCH] emit signal when starting and finishing to save a document --- src/App/Application.cpp | 12 ++++++++ src/App/Application.h | 6 ++++ src/App/Document.cpp | 4 +++ src/App/Document.h | 4 +++ src/App/DocumentObserverPython.cpp | 45 +++++++++++++++++++++++++++++- src/App/DocumentObserverPython.h | 6 ++++ src/Mod/Test/Document.py | 26 +++++++++++++++-- 7 files changed, 99 insertions(+), 4 deletions(-) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index bb415fa1e2..78d9c16acc 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -431,6 +431,8 @@ Document* Application::newDocument(const char * Name, const char * UserName) _pActiveDoc->signalOpenTransaction.connect(boost::bind(&App::Application::slotOpenTransaction, this, _1, _2)); _pActiveDoc->signalCommitTransaction.connect(boost::bind(&App::Application::slotCommitTransaction, this, _1)); _pActiveDoc->signalAbortTransaction.connect(boost::bind(&App::Application::slotAbortTransaction, this, _1)); + _pActiveDoc->signalStartSave.connect(boost::bind(&App::Application::slotStartSaveDocument, this, _1, _2)); + _pActiveDoc->signalFinishSave.connect(boost::bind(&App::Application::slotFinishSaveDocument, this, _1, _2)); // make sure that the active document is set in case no GUI is up { @@ -1055,6 +1057,16 @@ void Application::slotAbortTransaction(const Document& d) this->signalAbortTransaction(d); } +void Application::slotStartSaveDocument(const App::Document& doc, const std::string& filename) +{ + this->signalStartSaveDocument(doc, filename); +} + +void Application::slotFinishSaveDocument(const App::Document& doc, const std::string& filename) +{ + this->signalFinishSaveDocument(doc, filename); +} + //************************************************************************** // Init, Destruct and singleton diff --git a/src/App/Application.h b/src/App/Application.h index ed367b1d5c..cf86a88e0d 100644 --- a/src/App/Application.h +++ b/src/App/Application.h @@ -116,6 +116,10 @@ public: boost::signal signalStartRestoreDocument; /// signal on restoring Document boost::signal signalFinishRestoreDocument; + /// signal on starting to save Document + boost::signal signalStartSaveDocument; + /// signal on saved Document + boost::signal signalFinishSaveDocument; /// signal on undo in document boost::signal signalUndoDocument; /// signal on redo in document @@ -295,6 +299,8 @@ protected: void slotOpenTransaction(const App::Document&, std::string); void slotCommitTransaction(const App::Document&); void slotAbortTransaction(const App::Document&); + void slotStartSaveDocument(const App::Document&, const std::string&); + void slotFinishSaveDocument(const App::Document&, const std::string&); //@} private: diff --git a/src/App/Document.cpp b/src/App/Document.cpp index da196c18f6..eafa15d745 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -1661,6 +1661,8 @@ bool Document::save (void) bool Document::saveToFile(const char* filename) const { + signalStartSave(*this, filename); + auto hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document"); int compression = hGrp->GetInt("CompressionLevel",3); compression = Base::clamp(compression, Z_NO_COMPRESSION, Z_BEST_COMPRESSION); @@ -1758,6 +1760,8 @@ bool Document::saveToFile(const char* filename) const Base::Console().Warning("Cannot rename file from '%s' to '%s'\n", fn.c_str(), filename); + signalFinishSave(*this, filename); + return true; } diff --git a/src/App/Document.h b/src/App/Document.h index d2f2fdeb67..473bbcf5c5 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -152,6 +152,10 @@ public: Base::XMLReader&)> signalImportObjects; boost::signal&, Base::Reader&, const std::map&)> signalImportViewObjects; + //signal starting a save action to a file + boost::signal signalStartSave; + //signal finishing a save action to a file + boost::signal signalFinishSave; boost::signal signalRecomputed; boost::signal signalRecomputedObject; //signal a new opened transaction diff --git a/src/App/DocumentObserverPython.cpp b/src/App/DocumentObserverPython.cpp index 2dcbd7138d..7d1fa71256 100644 --- a/src/App/DocumentObserverPython.cpp +++ b/src/App/DocumentObserverPython.cpp @@ -97,6 +97,11 @@ DocumentObserverPython::DocumentObserverPython(const Py::Object& obj) : inst(obj this->connectDocumentAbortTransaction = App::GetApplication().signalAbortTransaction.connect(boost::bind (&DocumentObserverPython::slotAbortTransaction, this, _1)); + this->connectDocumentStartSave = App::GetApplication().signalStartSaveDocument.connect(boost::bind + (&DocumentObserverPython::slotStartSaveDocument, this, _1, _2)); + this->connectDocumentFinishSave = App::GetApplication().signalFinishSaveDocument.connect(boost::bind + (&DocumentObserverPython::slotFinishSaveDocument, this, _1, _2)); + this->connectObjectAppendDynamicProperty = App::GetApplication().signalAppendDynamicProperty.connect(boost::bind (&DocumentObserverPython::slotAppendDynamicProperty, this, _1)); this->connectObjectRemoveDynamicProperty = App::GetApplication().signalRemoveDynamicProperty.connect(boost::bind @@ -125,7 +130,9 @@ DocumentObserverPython::~DocumentObserverPython() this->connectDocumentOpenTransaction.disconnect(); this->connectDocumentCommitTransaction.disconnect(); this->connectDocumentAbortTransaction.disconnect(); - + this->connectDocumentStartSave.disconnect(); + this->connectDocumentFinishSave.disconnect(); + this->connectObjectAppendDynamicProperty.disconnect(); this->connectObjectRemoveDynamicProperty.disconnect(); this->connectObjectChangePropertyEditor.disconnect(); @@ -518,3 +525,39 @@ void DocumentObserverPython::slotChangePropertyEditor(const App::Property& Prop) e.ReportException(); } } + +void DocumentObserverPython::slotStartSaveDocument(const App::Document& doc, const std::string& file) +{ + Base::PyGILStateLocker lock; + try { + if (this->inst.hasAttr(std::string("slotStartSaveDocument"))) { + Py::Callable method(this->inst.getAttr(std::string("slotStartSaveDocument"))); + Py::Tuple args(2); + args.setItem(0, Py::Object(const_cast(doc).getPyObject(), true)); + args.setItem(1, Py::String(file)); + method.apply(args); + } + } + catch (Py::Exception&) { + Base::PyException e; // extract the Python error text + e.ReportException(); + } +} + +void DocumentObserverPython::slotFinishSaveDocument(const App::Document& doc, const std::string& file) +{ + Base::PyGILStateLocker lock; + try { + if (this->inst.hasAttr(std::string("slotFinishSaveDocument"))) { + Py::Callable method(this->inst.getAttr(std::string("slotFinishSaveDocument"))); + Py::Tuple args(2); + args.setItem(0, Py::Object(const_cast(doc).getPyObject(), true)); + args.setItem(1, Py::String(file)); + method.apply(args); + } + } + catch (Py::Exception&) { + Base::PyException e; // extract the Python error text + e.ReportException(); + } +} diff --git a/src/App/DocumentObserverPython.h b/src/App/DocumentObserverPython.h index aae0e8f34f..71643d9084 100644 --- a/src/App/DocumentObserverPython.h +++ b/src/App/DocumentObserverPython.h @@ -91,6 +91,10 @@ private: 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::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*/ + void slotFinishSaveDocument(const App::Document&, const std::string&); private: Py::Object inst; @@ -114,6 +118,8 @@ private: Connection connectDocumentOpenTransaction; Connection connectDocumentCommitTransaction; Connection connectDocumentAbortTransaction; + Connection connectDocumentStartSave; + Connection connectDocumentFinishSave; Connection connectObjectAppendDynamicProperty; Connection connectObjectRemoveDynamicProperty; Connection connectObjectChangePropertyEditor; diff --git a/src/Mod/Test/Document.py b/src/Mod/Test/Document.py index 976eb8a84b..dba5a80c4f 100644 --- a/src/Mod/Test/Document.py +++ b/src/Mod/Test/Document.py @@ -1406,7 +1406,17 @@ class DocumentObserverCases(unittest.TestCase): self.signal.append('ObjChangePropEdit'); self.parameter.append(obj) self.parameter2.append(prop) - + + def slotStartSaveDocument(self, obj, name): + self.signal.append('DocStartSave') + self.parameter.append(obj) + self.parameter2.append(name) + + def slotFinishSaveDocument(self, obj, name): + self.signal.append('DocFinishSave') + self.parameter.append(obj) + self.parameter2.append(name) + class GuiObserver(): signal = [] @@ -1458,6 +1468,16 @@ class DocumentObserverCases(unittest.TestCase): self.Obs = self.Observer(); FreeCAD.addDocumentObserver(self.Obs); + def testSave(self): + TempPath = tempfile.gettempdir() + SaveName = TempPath + os.sep + "SaveRestoreTests.FCStd" + self.Doc1 = FreeCAD.newDocument("Observer1"); + self.Doc1.saveAs(SaveName) + self.assertEqual(self.Obs.signal.pop(), 'DocFinishSave') + self.assertEqual(self.Obs.parameter2.pop(), self.Doc1.FileName) + self.assertEqual(self.Obs.signal.pop(), 'DocStartSave') + self.assertEqual(self.Obs.parameter2.pop(), self.Doc1.FileName) + def testDocument(self): # testing document level signals @@ -1577,13 +1597,13 @@ class DocumentObserverCases(unittest.TestCase): self.failUnless(self.Obs.parameter2.pop(0) == "Label") self.failUnless(not self.Obs.signal and not self.Obs.parameter and not self.Obs.parameter2) - obj.touch() + obj.enforceRecompute() obj.recompute() self.failUnless(self.Obs.signal.pop(0) == 'ObjRecomputed') self.failUnless(self.Obs.parameter.pop(0) is obj) self.failUnless(not self.Obs.signal and not self.Obs.parameter and not self.Obs.parameter2) - obj.touch() + obj.enforceRecompute() self.Doc1.recompute() self.failUnless(self.Obs.signal.pop(0) == 'ObjRecomputed') self.failUnless(self.Obs.parameter.pop(0) is obj)