prepare view provider for undo/redo

This commit is contained in:
wmayer 2016-06-20 12:50:21 +02:00
parent f0e00311cd
commit 9ec06b47c6
12 changed files with 181 additions and 70 deletions

View File

@ -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<Vertex,DocumentObject*>::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<DocumentObject*>::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);

View File

@ -116,6 +116,10 @@ public:
boost::signal<void (const App::DocumentObject&)> signalRelabelObject;
/// signal on activated Object
boost::signal<void (const App::DocumentObject&)> signalActivatedObject;
/// signal on created object
boost::signal<void (const App::DocumentObject&, Transaction*)> signalTransactionAppend;
/// signal on removed object
boost::signal<void (const App::DocumentObject&, Transaction*)> signalTransactionRemove;
/// signal on undo
boost::signal<void (const App::Document&)> signalUndo;
/// signal on redo

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -45,6 +45,7 @@
#include <App/Document.h>
#include <App/DocumentObject.h>
#include <App/DocumentObjectGroup.h>
#include <App/Transactions.h>
#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::BaseClass*>(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<ViewProviderDocumentObject*>(base);
d->_ViewProviderMap[&Obj] = pcProvider;
ViewProviderDocumentObject* pcProvider = static_cast<ViewProviderDocumentObject*>(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<App::DocumentObject*>(&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::BaseClass*>(Base::Type::createInstanceByName(cName.c_str(),true));
if (base) {
// type not derived from ViewProviderDocumentObject!!!
assert(base->getTypeId().isDerivedFrom(Gui::ViewProviderDocumentObject::getClassTypeId()));
pcProvider = static_cast<ViewProviderDocumentObject*>(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<App::DocumentObject*>(&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<Gui::BaseView*>::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<ViewProviderDocumentObject*>(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 App::DocumentObject*,ViewProviderDocumentObject*>::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;

View File

@ -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<std::string> listRedoNames;
//@}
friend class TransactionViewProvider;
};
} // namespace Gui

View File

@ -25,7 +25,12 @@
#ifndef _PreComp_
#endif
#include "Application.h"
#include "Document.h"
#include "TransactionObject.h"
#include "ViewProviderDocumentObject.h"
#include <App/Document.h>
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<ViewProviderDocumentObject*>(pcObj));
}
}
}
void TransactionViewProvider::applyDel(App::Document& /*Doc*/, App::TransactionalObject* /*pcObj*/)
void TransactionViewProvider::applyDel(App::Document& Doc, App::TransactionalObject* pcObj)
{
// nothing to do here
}

View File

@ -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)

View File

@ -27,6 +27,7 @@
#include <map>
#include <vector>
#include <string>
#include <bitset>
#include <QIcon>
#include <boost/signals.hpp>
@ -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<std::string, int> _sDisplayMaskModes;
bool _updateData;
// friends
friend class ViewProviderPythonFeaturePy;

View File

@ -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)

View File

@ -97,7 +97,6 @@ public:
virtual void drop(const std::vector<const App::DocumentObject*> &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.