00001 /*========================================================================= 00002 00003 Program: Medical Imaging & Interaction Toolkit 00004 Language: C++ 00005 Date: $Date$ 00006 Version: $Revision$ 00007 00008 Copyright (c) German Cancer Research Center, Division of Medical and 00009 Biological Informatics. All rights reserved. 00010 See MITKCopyright.txt or https://www.mitk.org/copyright.html for details. 00011 00012 This software is distributed WITHOUT ANY WARRANTY; without even 00013 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 00014 PURPOSE. See the above copyright notices for more information. 00015 00016 =========================================================================*/ 00017 00018 00019 #include "mitkLimitedLinearUndo.h" 00020 #include <mitkRenderingManager.h> 00021 00022 mitk::LimitedLinearUndo::LimitedLinearUndo() 00023 { 00024 // nothing to do 00025 } 00026 00027 mitk::LimitedLinearUndo::~LimitedLinearUndo() 00028 { 00029 //delete undo and redo list 00030 this->ClearList(&m_UndoList); 00031 this->ClearList(&m_RedoList); 00032 } 00033 00034 void mitk::LimitedLinearUndo::ClearList(UndoContainer* list) 00035 { 00036 while(!list->empty()) 00037 { 00038 UndoStackItem* item = list->back(); 00039 list->pop_back(); 00040 delete item; 00041 } 00042 } 00043 00044 bool mitk::LimitedLinearUndo::SetOperationEvent(UndoStackItem* stackItem) 00045 { 00046 OperationEvent* operationEvent = dynamic_cast<OperationEvent*>(stackItem); 00047 if (!operationEvent) return false; 00048 00049 // clear the redolist, if a new operation is saved 00050 if (!m_RedoList.empty()) 00051 { 00052 this->ClearList(&m_RedoList); 00053 InvokeEvent( RedoEmptyEvent() ); 00054 } 00055 00056 m_UndoList.push_back(operationEvent); 00057 00058 InvokeEvent( UndoNotEmptyEvent() ); 00059 00060 return true; 00061 } 00062 00063 bool mitk::LimitedLinearUndo::Undo(bool fine) 00064 { 00065 if (fine) 00066 { 00067 // undo one object event ID 00068 return Undo(); 00069 } 00070 else 00071 { 00072 // undo one group event ID 00073 int oeid = FirstObjectEventIdOfCurrentGroup(m_UndoList); // get the Object Event ID of the first item with a differnt Group ID (as seen from the end of stack) 00074 return Undo(oeid); 00075 } 00076 } 00077 00078 bool mitk::LimitedLinearUndo::Undo() 00079 { 00080 if(m_UndoList.empty()) return false; 00081 00082 int undoObjectEventId = m_UndoList.back()->GetObjectEventId(); 00083 return Undo( undoObjectEventId ); 00084 } 00085 00086 bool mitk::LimitedLinearUndo::Undo(int oeid) 00087 { 00088 if(m_UndoList.empty()) return false; 00089 00090 do 00091 { 00092 m_UndoList.back()->ReverseAndExecute(); 00093 00094 m_RedoList.push_back(m_UndoList.back()); // move to redo stack 00095 m_UndoList.pop_back(); 00096 InvokeEvent( RedoNotEmptyEvent() ); 00097 00098 if (m_UndoList.empty()) 00099 { 00100 InvokeEvent( UndoEmptyEvent() ); 00101 return false; 00102 } 00103 } 00104 while ( m_UndoList.back()->GetObjectEventId() >= oeid ); 00105 00106 //Update. Check Rendering Mechanism where to request updates 00107 mitk::RenderingManager::GetInstance()->RequestUpdateAll(); 00108 return true; 00109 } 00110 00111 bool mitk::LimitedLinearUndo::Redo(bool) 00112 { 00113 return Redo(); 00114 } 00115 00116 bool mitk::LimitedLinearUndo::Redo() 00117 { 00118 if (m_RedoList.empty()) return false; 00119 00120 int redoObjectEventId = m_RedoList.back()->GetObjectEventId(); 00121 return Redo( redoObjectEventId ); 00122 } 00123 00124 bool mitk::LimitedLinearUndo::Redo(int oeid) 00125 { 00126 if (m_RedoList.empty()) return false; 00127 00128 do 00129 { 00130 m_RedoList.back()->ReverseAndExecute(); 00131 00132 m_UndoList.push_back(m_RedoList.back()); 00133 m_RedoList.pop_back(); 00134 InvokeEvent( UndoNotEmptyEvent() ); 00135 00136 if (m_RedoList.empty()) 00137 { 00138 InvokeEvent( RedoEmptyEvent() ); 00139 break; 00140 } 00141 } 00142 while ( m_RedoList.back()->GetObjectEventId() <= oeid ); 00143 00144 //Update. This should belong into the ExecuteOperation() of OperationActors, but it seems not to be used everywhere 00145 mitk::RenderingManager::GetInstance()->RequestUpdateAll(); 00146 return true; 00147 } 00148 00149 void mitk::LimitedLinearUndo::Clear() 00150 { 00151 this->ClearList(&m_UndoList); 00152 InvokeEvent( UndoEmptyEvent() ); 00153 00154 this->ClearList(&m_RedoList); 00155 InvokeEvent( RedoEmptyEvent() ); 00156 } 00157 00158 void mitk::LimitedLinearUndo::ClearRedoList() 00159 { 00160 this->ClearList(&m_RedoList); 00161 InvokeEvent( RedoEmptyEvent() ); 00162 } 00163 00164 bool mitk::LimitedLinearUndo::RedoListEmpty() 00165 { 00166 return m_RedoList.empty(); 00167 } 00168 00169 int mitk::LimitedLinearUndo::GetLastObjectEventIdInList() 00170 { 00171 return m_UndoList.back()->GetObjectEventId(); 00172 } 00173 00174 int mitk::LimitedLinearUndo::GetLastGroupEventIdInList() 00175 { 00176 return m_UndoList.back()->GetGroupEventId(); 00177 } 00178 00179 mitk::OperationEvent* mitk::LimitedLinearUndo::GetLastOfType(OperationActor* destination, OperationType opType) 00180 { 00181 // When/where is this function needed? In CoordinateSupplier... 00182 for ( UndoContainerRevIter iter = m_UndoList.rbegin(); iter != m_UndoList.rend(); ++iter ) 00183 { 00184 OperationEvent* opEvent = dynamic_cast<OperationEvent*>(*iter); 00185 if (!opEvent) continue; 00186 00187 if ( opEvent->GetOperation() != NULL 00188 && opEvent->GetOperation()->GetOperationType() == opType 00189 && opEvent->IsValid() 00190 && opEvent->GetDestination() == destination ) 00191 return opEvent; 00192 } 00193 00194 return NULL; 00195 } 00196 00197 int mitk::LimitedLinearUndo::FirstObjectEventIdOfCurrentGroup(mitk::LimitedLinearUndo::UndoContainer& stack) 00198 { 00199 int currentGroupEventId = stack.back()->GetGroupEventId(); 00200 int firstObjectEventId = -1; 00201 00202 for ( UndoContainerRevIter iter = stack.rbegin(); iter != stack.rend(); ++iter ) 00203 { 00204 if ( (*iter)->GetGroupEventId() == currentGroupEventId ) 00205 { 00206 firstObjectEventId = (*iter)->GetObjectEventId(); 00207 } 00208 else break; 00209 } 00210 00211 return firstObjectEventId; 00212 } 00213