/*========================================================================= Program: ParaView Module: vtkSMUndoStack.cxx Copyright (c) Kitware, Inc. All rights reserved. See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkSMUndoStack.h" #include "vtkCollection.h" #include "vtkCommand.h" #include "vtkObjectFactory.h" #include "vtkProcessModule.h" #include "vtkPVXMLElement.h" #include "vtkSMMessage.h" #include "vtkSMProxyManager.h" #include "vtkSMSession.h" #include "vtkSMUndoElement.h" #include "vtkUndoSet.h" #include "vtkUndoStackInternal.h" #include "vtkSMStateLocator.h" #include "vtkSMProxyLocator.h" #include "vtkSMProxyManager.h" #include "vtkSMDeserializerProtobuf.h" #include "vtkSMRemoteObjectUpdateUndoElement.h" #include #include #include "vtkNew.h" //***************************************************************************** class vtkSMUndoStack::vtkInternal { public: typedef std::set > SessionSetType; SessionSetType Sessions; vtkNew UndoSetProxyLocator; vtkNew UndoSetProxyDeserializer; vtkNew UndoSetStateLocator; vtkInternal() { this->UndoSetProxyDeserializer->SetStateLocator( this->UndoSetStateLocator.GetPointer()); this->UndoSetProxyLocator->SetDeserializer( this->UndoSetProxyDeserializer.GetPointer()); this->UndoSetProxyLocator->UseSessionToLocateProxy(true); } void FillLocatorWithUndoStates(vtkUndoSet* undoSet, bool useBeforeState) { this->UndoSetStateLocator->UnRegisterAllStates(false); int max = undoSet->GetNumberOfElements(); for (int cc=0; cc < max; ++cc) { vtkSMRemoteObjectUpdateUndoElement* elem = vtkSMRemoteObjectUpdateUndoElement::SafeDownCast( undoSet->GetElement(cc)); if(elem) { elem->SetProxyLocator(this->UndoSetProxyLocator.GetPointer()); if(useBeforeState) { this->UndoSetStateLocator->RegisterState(elem->BeforeState); } else { this->UndoSetStateLocator->RegisterState(elem->AfterState); } } } } void UpdateSessions(vtkUndoSet* undoSet) { int max = undoSet->GetNumberOfElements(); this->Sessions.clear(); for (int cc=0; cc < max; ++cc) { vtkSMUndoElement* elem = vtkSMUndoElement::SafeDownCast(undoSet->GetElement(cc)); if(elem->GetSession()) { this->Sessions.insert(elem->GetSession()); } } assert("Undo element should not involve more than one session" && this->Sessions.size() < 2); if(this->Sessions.size() == 1) { this->UndoSetStateLocator->SetParentLocator(this->Sessions.begin()->GetPointer()->GetStateLocator()); } } void FillSessionsRemoteObjects(vtkCollection* collection) { SessionSetType::iterator iter = this->Sessions.begin(); while(iter != this->Sessions.end()) { iter->GetPointer()->GetAllRemoteObjects(collection); iter++; } } void Clear() { this->ClearProxyLocators(); this->Sessions.clear(); } void ClearProxyLocators() { this->UndoSetProxyLocator->Clear(); SessionSetType::iterator iter = this->Sessions.begin(); while(iter != this->Sessions.end()) { iter->GetPointer()->GetProxyLocator()->Clear(); iter++; } } }; //***************************************************************************** vtkStandardNewMacro(vtkSMUndoStack); //----------------------------------------------------------------------------- vtkSMUndoStack::vtkSMUndoStack() { this->Internal = new vtkInternal(); } //----------------------------------------------------------------------------- vtkSMUndoStack::~vtkSMUndoStack() { delete this->Internal; this->Internal = NULL; } //----------------------------------------------------------------------------- void vtkSMUndoStack::Push(const char* label, vtkUndoSet* changeSet) { this->Superclass::Push(label, changeSet); this->InvokeEvent(PushUndoSetEvent, changeSet); } //----------------------------------------------------------------------------- int vtkSMUndoStack::Undo() { if (!this->CanUndo()) { vtkErrorMacro("Cannot undo. Nothing on undo stack."); return 0; } // Hold remote objects refs while the UndoSet is processing vtkNew remoteObjectsCollection; this->FillWithRemoteObjects(this->GetNextUndoSet(), remoteObjectsCollection.GetPointer()); this->Internal->FillLocatorWithUndoStates(this->GetNextUndoSet(), true); int retValue = this->Superclass::Undo(); this->Internal->Clear(); return retValue; } //----------------------------------------------------------------------------- int vtkSMUndoStack::Redo() { if (!this->CanRedo()) { vtkErrorMacro("Cannot redo. Nothing on redo stack."); return 0; } // Hold remote objects refs while the UndoSet is processing vtkNew remoteObjectsCollection; this->FillWithRemoteObjects(this->GetNextRedoSet(), remoteObjectsCollection.GetPointer()); this->Internal->FillLocatorWithUndoStates(this->GetNextRedoSet(), false); int retValue = this->Superclass::Redo(); this->Internal->Clear(); return retValue; } //----------------------------------------------------------------------------- void vtkSMUndoStack::FillWithRemoteObjects( vtkUndoSet *undoSet, vtkCollection *collection) { if(!undoSet || !collection) return; this->Internal->UpdateSessions(undoSet); this->Internal->FillSessionsRemoteObjects(collection); } //----------------------------------------------------------------------------- void vtkSMUndoStack::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); }