prepare view provider for undo/redo
This commit is contained in:
parent
f0e00311cd
commit
9ec06b47c6
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue
Block a user