diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 2c58447b9..a561c46ec 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -1937,6 +1937,12 @@ DocumentObject * Document::addObject(const char* sType, const char* pObjectName, // mark the object as new (i.e. set status bit 2) and send the signal pcObject->StatusBits.set(2); signalNewObject(*pcObject); + + // do no transactions if we do a rollback! + if (!d->rollback && d->activeUndoTransaction) { + signalTransactionAppend(*pcObject, d->activeUndoTransaction); + } + signalActivatedObject(*pcObject); // return the Object @@ -1979,6 +1985,12 @@ void Document::addObject(DocumentObject* pcObject, const char* pObjectName) // mark the object as new (i.e. set status bit 2) and send the signal pcObject->StatusBits.set(2); signalNewObject(*pcObject); + + // do no transactions if we do a rollback! + if (!d->rollback && d->activeUndoTransaction) { + signalTransactionAppend(*pcObject, d->activeUndoTransaction); + } + signalActivatedObject(*pcObject); } @@ -1991,14 +2003,20 @@ void Document::_addObject(DocumentObject* pcObject, const char* pObjectName) pcObject->pcNameInDocument = &(d->objectMap.find(ObjectName)->first); // do no transactions if we do a rollback! - if(!d->rollback){ + if (!d->rollback) { // Undo stuff if (d->activeUndoTransaction) d->activeUndoTransaction->addObjectDel(pcObject); } + // send the signal signalNewObject(*pcObject); + // do no transactions if we do a rollback! + if (!d->rollback && d->activeUndoTransaction) { + signalTransactionAppend(*pcObject, d->activeUndoTransaction); + } + d->activeObject = pcObject; signalActivatedObject(*pcObject); } @@ -2022,9 +2040,20 @@ void Document::remObject(const char* sName) if (!d->undoing && !d->rollback) { pos->second->unsetupObject(); } + signalDeletedObject(*(pos->second)); pos->second->StatusBits.reset (ObjectStatus::Delete); // Unset the bit to be on the safe side + // do no transactions if we do a rollback! + if (!d->rollback && d->activeUndoTransaction) { + // in this case transaction delete or save the object + signalTransactionRemove(*pos->second, d->activeUndoTransaction); + } + else { + // if not saved in undo -> delete object + signalTransactionRemove(*pos->second, 0); + } + if (!d->vertexMap.empty()) { // recompute of document is running for (std::map::iterator it = d->vertexMap.begin(); it != d->vertexMap.end(); ++it) { @@ -2051,9 +2080,10 @@ void Document::remObject(const char* sName) // in this case transaction delete or save the object d->activeUndoTransaction->addObjectNew(pos->second); } - else + else { // if not saved in undo -> delete object delete pos->second; + } } for (std::vector::iterator obj = d->objectArray.begin(); obj != d->objectArray.end(); ++obj) { @@ -2098,9 +2128,12 @@ void Document::_remObject(DocumentObject* pcObject) // do no transactions if we do a rollback! if (!d->rollback) { // Undo stuff - if (d->activeUndoTransaction) + if (d->activeUndoTransaction) { + signalTransactionRemove(*pcObject, d->activeUndoTransaction); d->activeUndoTransaction->addObjectNew(pcObject); + } } + // remove from map d->objectMap.erase(pos); diff --git a/src/App/Document.h b/src/App/Document.h index fdaeb2cb4..6f7f375eb 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -116,6 +116,10 @@ public: boost::signal signalRelabelObject; /// signal on activated Object boost::signal signalActivatedObject; + /// signal on created object + boost::signal signalTransactionAppend; + /// signal on removed object + boost::signal signalTransactionRemove; /// signal on undo boost::signal signalUndo; /// signal on redo diff --git a/src/App/TransactionalObject.cpp b/src/App/TransactionalObject.cpp index e118ccd59..be12edfc7 100644 --- a/src/App/TransactionalObject.cpp +++ b/src/App/TransactionalObject.cpp @@ -44,6 +44,16 @@ TransactionalObject::~TransactionalObject(void) { } +bool TransactionalObject::isAttachedToDocument() const +{ + return false; +} + +const char* TransactionalObject::detachFromDocument() +{ + return ""; +} + void TransactionalObject::onBeforeChangeProperty(Document *doc, const Property *prop) { doc->onBeforeChangeProperty(this, prop); diff --git a/src/App/TransactionalObject.h b/src/App/TransactionalObject.h index 6b84164d3..a8878e2dd 100644 --- a/src/App/TransactionalObject.h +++ b/src/App/TransactionalObject.h @@ -42,8 +42,8 @@ public: /// Constructor TransactionalObject(void); virtual ~TransactionalObject(); - virtual bool isAttachedToDocument() const = 0; - virtual const char* detachFromDocument() = 0; + virtual bool isAttachedToDocument() const; + virtual const char* detachFromDocument(); protected: void onBeforeChangeProperty(Document *doc, const Property *prop); diff --git a/src/App/Transactions.h b/src/App/Transactions.h index 8e70f9cf9..ee1a9b5a2 100644 --- a/src/App/Transactions.h +++ b/src/App/Transactions.h @@ -67,9 +67,6 @@ public: /// check if this object is used in a transaction bool hasObject(const TransactionalObject *Obj) const; - friend class Document; - -protected: void addObjectNew(TransactionalObject *Obj); void addObjectDel(const TransactionalObject *Obj); void addObjectChange(const TransactionalObject *Obj, const Property *Prop); diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index f037e46c9..bfbbf6911 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include "Application.h" #include "MainWindow.h" @@ -99,6 +100,8 @@ struct DocumentP Connection connectImportObjects; Connection connectUndoDocument; Connection connectRedoDocument; + Connection connectTransactionAppend; + Connection connectTransactionRemove; }; } // namespace Gui @@ -149,8 +152,12 @@ Document::Document(App::Document* pcDocument,Application * app) d->connectUndoDocument = pcDocument->signalUndo.connect (boost::bind(&Gui::Document::slotUndoDocument, this, _1)); d->connectRedoDocument = pcDocument->signalRedo.connect - (boost::bind(&Gui::Document::slotRedoDocument, this, _1)); + (boost::bind(&Gui::Document::slotRedoDocument, this, _1)); + d->connectTransactionAppend = pcDocument->signalTransactionAppend.connect + (boost::bind(&Gui::Document::slotTransactionAppend, this, _1, _2)); + d->connectTransactionRemove = pcDocument->signalTransactionRemove.connect + (boost::bind(&Gui::Document::slotTransactionRemove, this, _1, _2)); // pointer to the python class // NOTE: As this Python object doesn't get returned to the interpreter we // mustn't increment it (Werner Jan-12-2006) @@ -181,6 +188,8 @@ Document::~Document() d->connectImportObjects.disconnect(); d->connectUndoDocument.disconnect(); d->connectRedoDocument.disconnect(); + d->connectTransactionAppend.disconnect(); + d->connectTransactionRemove.disconnect(); // e.g. if document gets closed from within a Python command d->_isClosing = true; @@ -390,41 +399,49 @@ void Document::setPos(const char* name, const Base::Matrix4D& rclMtrx) //***************************************************************************************************** void Document::slotNewObject(const App::DocumentObject& Obj) { - //Base::Console().Log("Document::slotNewObject() called\n"); - std::string cName = Obj.getViewProviderName(); - if (cName.empty()) { - // handle document object with no view provider specified - Base::Console().Log("%s has no view provider specified\n", Obj.getTypeId().getName()); - return; - } - - setModified(true); - Base::BaseClass* base = static_cast(Base::Type::createInstanceByName(cName.c_str(),true)); - if (base) { - // type not derived from ViewProviderDocumentObject!!! - assert(base->getTypeId().isDerivedFrom(Gui::ViewProviderDocumentObject::getClassTypeId())); - ViewProviderDocumentObject *pcProvider = static_cast(base); - d->_ViewProviderMap[&Obj] = pcProvider; + ViewProviderDocumentObject* pcProvider = static_cast(getViewProvider(&Obj)); + if (!pcProvider) { + //Base::Console().Log("Document::slotNewObject() called\n"); + std::string cName = Obj.getViewProviderName(); + if (cName.empty()) { + // handle document object with no view provider specified + Base::Console().Log("%s has no view provider specified\n", Obj.getTypeId().getName()); + return; + } - try { - // if succesfully created set the right name and calculate the view - //FIXME: Consider to change argument of attach() to const pointer - pcProvider->attach(const_cast(&Obj)); - pcProvider->updateView(); - pcProvider->setActiveMode(); - } - catch(const Base::MemoryException& e){ - Base::Console().Error("Memory exception in '%s' thrown: %s\n",Obj.getNameInDocument(),e.what()); - } - catch(Base::Exception &e){ - e.ReportException(); - } + setModified(true); + Base::BaseClass* base = static_cast(Base::Type::createInstanceByName(cName.c_str(),true)); + if (base) { + // type not derived from ViewProviderDocumentObject!!! + assert(base->getTypeId().isDerivedFrom(Gui::ViewProviderDocumentObject::getClassTypeId())); + pcProvider = static_cast(base); + d->_ViewProviderMap[&Obj] = pcProvider; + + try { + // if succesfully created set the right name and calculate the view + //FIXME: Consider to change argument of attach() to const pointer + pcProvider->attach(const_cast(&Obj)); + pcProvider->updateView(); + pcProvider->setActiveMode(); + } + catch(const Base::MemoryException& e){ + Base::Console().Error("Memory exception in '%s' thrown: %s\n",Obj.getNameInDocument(),e.what()); + } + catch(Base::Exception &e){ + e.ReportException(); + } #ifndef FC_DEBUG - catch(...){ - Base::Console().Error("App::Document::_RecomputeFeature(): Unknown exception in Feature \"%s\" thrown\n",Obj.getNameInDocument()); - } + catch(...){ + Base::Console().Error("App::Document::_RecomputeFeature(): Unknown exception in Feature \"%s\" thrown\n",Obj.getNameInDocument()); + } #endif + } + else { + Base::Console().Warning("Gui::Document::slotNewObject() no view provider for the object %s found\n",cName.c_str()); + } + } + if (pcProvider) { std::list::iterator vIt; // cycling to all views of the document for (vIt = d->baseViews.begin();vIt != d->baseViews.end();++vIt) { @@ -436,12 +453,9 @@ void Document::slotNewObject(const App::DocumentObject& Obj) // adding to the tree signalNewObject(*pcProvider); - // it is possible that a new viewprovider aready claims children + // it is possible that a new viewprovider already claims children handleChildren3D(pcProvider); } - else { - Base::Console().Warning("Gui::Document::slotNewObject() no view provider for the object %s found\n",cName.c_str()); - } } void Document::slotDeletedObject(const App::DocumentObject& Obj) @@ -469,9 +483,6 @@ void Document::slotDeletedObject(const App::DocumentObject& Obj) // removing from tree signalDeletedObject(*(static_cast(viewProvider))); - - delete viewProvider; - d->_ViewProviderMap.erase(&Obj); } } @@ -514,6 +525,30 @@ void Document::slotRelabelObject(const App::DocumentObject& Obj) } } +void Document::slotTransactionAppend(const App::DocumentObject& obj, App::Transaction* transaction) +{ + ViewProvider* viewProvider = getViewProvider(&obj); + if (viewProvider && viewProvider->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) { + transaction->addObjectDel(viewProvider); + } +} + +void Document::slotTransactionRemove(const App::DocumentObject& obj, App::Transaction* transaction) +{ + std::map::const_iterator + it = d->_ViewProviderMap.find(&obj); + if (it != d->_ViewProviderMap.end()) { + ViewProvider* viewProvider = it->second; + d->_ViewProviderMap.erase(&obj); + // transaction being a nullptr indicates that undo/redo is off and the object + // can be safely deleted + if (transaction) + transaction->addObjectNew(viewProvider); + else + delete viewProvider; + } +} + void Document::slotActivatedObject(const App::DocumentObject& Obj) { ViewProvider* viewProvider = getViewProvider(&Obj); @@ -538,6 +573,18 @@ void Document::slotRedoDocument(const App::Document& doc) signalRedoDocument(*this); } +void Document::addViewProvider(Gui::ViewProviderDocumentObject* vp) +{ + vp->setStatus(Detach, false); + d->_ViewProviderMap[vp->getObject()] = vp; +} + +void Document::removeViewProvider(Gui::ViewProviderDocumentObject* vp) +{ + vp->setStatus(Detach, true); + d->_ViewProviderMap.erase(vp->getObject()); +} + void Document::setModified(bool b) { d->_isModified = b; diff --git a/src/Gui/Document.h b/src/Gui/Document.h index db0fd6ae9..43a216fbb 100644 --- a/src/Gui/Document.h +++ b/src/Gui/Document.h @@ -51,6 +51,7 @@ class ViewProvider; class ViewProviderDocumentObject; class Application; class DocumentPy; +class TransactionViewProvider; enum HighlightMode; /** The Gui Document @@ -75,6 +76,8 @@ protected: void slotDeletedObject(const App::DocumentObject&); void slotChangedObject(const App::DocumentObject&, const App::Property&); void slotRelabelObject(const App::DocumentObject&); + void slotTransactionAppend(const App::DocumentObject&, App::Transaction*); + void slotTransactionRemove(const App::DocumentObject&, App::Transaction*); void slotActivatedObject(const App::DocumentObject&); void slotStartRestoreDocument(const App::Document&); void slotFinishRestoreDocument(const App::Document&); @@ -82,6 +85,9 @@ protected: void slotRedoDocument(const App::Document&); //@} + void addViewProvider(Gui::ViewProviderDocumentObject*); + void removeViewProvider(Gui::ViewProviderDocumentObject*); + public: /** @name Signals of the document */ //@{ @@ -254,6 +260,8 @@ private: /// redo names list std::list listRedoNames; //@} + + friend class TransactionViewProvider; }; } // namespace Gui diff --git a/src/Gui/TransactionObject.cpp b/src/Gui/TransactionObject.cpp index 5f9c68bb9..380d78202 100644 --- a/src/Gui/TransactionObject.cpp +++ b/src/Gui/TransactionObject.cpp @@ -25,7 +25,12 @@ #ifndef _PreComp_ #endif + +#include "Application.h" +#include "Document.h" #include "TransactionObject.h" +#include "ViewProviderDocumentObject.h" +#include using namespace Gui; @@ -40,10 +45,17 @@ TransactionViewProvider::~TransactionViewProvider() { } -void TransactionViewProvider::applyNew(App::Document& /*Doc*/, App::TransactionalObject* /*pcObj*/) +void TransactionViewProvider::applyNew(App::Document& Doc, App::TransactionalObject* pcObj) { + if (status == New) { + Gui::Document* doc = Application::Instance->getDocument(&Doc); + if (doc) { + doc->addViewProvider(static_cast(pcObj)); + } + } } -void TransactionViewProvider::applyDel(App::Document& /*Doc*/, App::TransactionalObject* /*pcObj*/) +void TransactionViewProvider::applyDel(App::Document& Doc, App::TransactionalObject* pcObj) { + // nothing to do here } diff --git a/src/Gui/ViewProvider.cpp b/src/Gui/ViewProvider.cpp index 72e01ef5e..09fcdb600 100644 --- a/src/Gui/ViewProvider.cpp +++ b/src/Gui/ViewProvider.cpp @@ -69,8 +69,9 @@ ViewProvider::ViewProvider() , _iActualMode(-1) , _iEditMode(-1) , viewOverrideMode(-1) - , _updateData(true) { + setStatus(UpdateData, true); + pcRoot = new SoSeparator(); pcRoot->ref(); pcModeSwitch = new SoSwitch(); @@ -139,12 +140,12 @@ void ViewProvider::unsetEditViewer(View3DInventorViewer*) bool ViewProvider::isUpdatesEnabled () const { - return _updateData; + return testStatus(UpdateData); } void ViewProvider::setUpdatesEnabled (bool enable) { - _updateData = enable; + setStatus(UpdateData, enable); } void highlight(const HighlightMode& high) diff --git a/src/Gui/ViewProvider.h b/src/Gui/ViewProvider.h index 4c93ce247..2327605e2 100644 --- a/src/Gui/ViewProvider.h +++ b/src/Gui/ViewProvider.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -68,6 +69,11 @@ class View3DInventorViewer; class ViewProviderPy; class ObjectItem; +enum ViewStatus { + UpdateData = 0, + Detach = 1 +}; + /** General interface for all visual stuff in FreeCAD @@ -210,20 +216,14 @@ public: bool isUpdatesEnabled () const; void setUpdatesEnabled (bool enable); + /// return the status bits + unsigned long getStatus() const {return StatusBits.to_ulong();} + bool testStatus(ViewStatus pos) const {return StatusBits.test((size_t)pos);} + void setStatus(ViewStatus pos, bool on) {StatusBits.set((size_t)pos, on);} + std::string toString() const; PyObject* getPyObject(); - /** @name Transaction handling - */ - //@{ - virtual bool isAttachedToDocument() const { - return false; - } - virtual const char* detachFromDocument() { - return 0; - } - //@} - /** @name Display mode methods */ //@{ @@ -361,6 +361,7 @@ protected: SoSeparator *pcAnnotation; ViewProviderPy* pyViewObject; std::string overrideMode; + std::bitset<32> StatusBits; private: void setModeSwitch(); @@ -369,7 +370,6 @@ private: int viewOverrideMode; std::string _sCurrentMode; std::map _sDisplayMaskModes; - bool _updateData; // friends friend class ViewProviderPythonFeaturePy; diff --git a/src/Gui/ViewProviderDocumentObject.cpp b/src/Gui/ViewProviderDocumentObject.cpp index ca98a1442..8e799ff34 100644 --- a/src/Gui/ViewProviderDocumentObject.cpp +++ b/src/Gui/ViewProviderDocumentObject.cpp @@ -81,15 +81,15 @@ void ViewProviderDocumentObject::finishRestoring() bool ViewProviderDocumentObject::isAttachedToDocument() const { - App::DocumentObject* obj = getObject(); - bool ok = obj ? obj->isAttachedToDocument() : false; - return ok; + return (!testStatus(Detach)); } const char* ViewProviderDocumentObject::detachFromDocument() { - App::DocumentObject* obj = getObject(); - return obj ? obj->getNameInDocument() : 0; + // here we can return an empty string since the object + // name comes from the document object + setStatus(Detach, true); + return ""; } void ViewProviderDocumentObject::onBeforeChange(const App::Property* prop) diff --git a/src/Gui/ViewProviderDocumentObject.h b/src/Gui/ViewProviderDocumentObject.h index 5be67bc14..501018c7c 100644 --- a/src/Gui/ViewProviderDocumentObject.h +++ b/src/Gui/ViewProviderDocumentObject.h @@ -97,7 +97,6 @@ public: virtual void drop(const std::vector &objList,Qt::KeyboardModifiers keys,Qt::MouseButtons mouseBts,const QPoint &pos); //@} - protected: /*! Get the active mdi view of the document this view provider is part of. @note The returned mdi view doesn't need to be a 3d view but can be e.g.