1 
2 
3 #include "tundo.h"
4 #include <deque>
5 
6 //-----------------------------------------------------------------------------
7 
8 namespace {
9 
deleteUndo(const TUndo * undo)10 void deleteUndo(const TUndo *undo) { delete undo; }
callUndo(const TUndo * undo)11 void callUndo(const TUndo *undo) { undo->undo(); }
callRedo(const TUndo * undo)12 void callRedo(const TUndo *undo) { undo->redo(); }
13 // void callRepeat(const TUndo* undo) {undo->repeat(); }
14 
15 class TUndoBlock final : public TUndo {
16   std::vector<TUndo *> m_undos;
17   typedef std::vector<TUndo *>::const_iterator Iterator;
18   typedef std::vector<TUndo *>::const_reverse_iterator ReverseIterator;
19   mutable bool m_deleted, m_undoing;
20 
21 public:
TUndoBlock()22   TUndoBlock() : m_deleted(false), m_undoing(false) {}
~TUndoBlock()23   ~TUndoBlock() {
24     assert(m_undoing == false);
25     assert(m_deleted == false);
26     m_deleted = true;
27     std::for_each(m_undos.begin(), m_undos.end(), deleteUndo);
28     m_undos.clear();
29   }
30 
getSize() const31   int getSize() const override {
32     int size = sizeof(*this);
33     for (Iterator cit = m_undos.begin(); cit != m_undos.end(); ++cit)
34       size += (*cit)->getSize();
35     size += (m_undos.capacity() - m_undos.size()) * sizeof(TUndo *);
36     return size;
37   }
getUndoCount() const38   int getUndoCount() const { return (int)m_undos.size(); }
setLast()39   void setLast() {
40     for (UINT i = 0; i < m_undos.size(); i++) {
41       m_undos[i]->m_isLastInBlock     = (i == 0);
42       m_undos[i]->m_isLastInRedoBlock = (i == m_undos.size() - 1);
43     }
44   }
45 
undo() const46   void undo() const override {
47     assert(!m_deleted);
48     assert(!m_undoing);
49     m_undoing = true;
50     // VERSIONE CORRETTA
51     std::for_each(m_undos.rbegin(), m_undos.rend(), callUndo);
52     // VERSIONE SBAGLIATA
53     // for_each(m_undos.begin(), m_undos.end(), callUndo);
54     m_undoing = false;
55   }
redo() const56   void redo() const override {
57     assert(!m_deleted);
58     // VERSIONE CORRETTA
59     std::for_each(m_undos.begin(), m_undos.end(), callRedo);
60     // VERSIONE SBAGLIATA
61     // for_each(m_undos.rbegin(), m_undos.rend(), callRedo);
62   }
63 
64   // void repeat() const {
65   //  for_each(m_undos.begin(), m_undos.end(), callRepeat);
66   //}
onAdd()67   void onAdd() override {}
add(TUndo * undo)68   void add(TUndo *undo) {
69     undo->m_isLastInBlock     = true;
70     undo->m_isLastInRedoBlock = true;
71     m_undos.push_back(undo);
72   }
73 
popUndo(int n)74   void popUndo(int n) {
75     if (n == -1) n = m_undos.size();
76     if (m_undos.empty() || n <= 0) return;
77     while (n > 0 && !m_undos.empty()) {
78       TUndo *undo = m_undos.back();
79       m_undos.pop_back();
80       delete undo;
81       n--;
82     }
83   }
84 
getHistoryString()85   QString getHistoryString() override {
86     if (m_undos.empty())
87       return TUndo::getHistoryString();
88     else if ((int)m_undos.size() == 1)
89       return m_undos.back()->getHistoryString();
90     else {
91       return QString("%1  etc..").arg(m_undos.back()->getHistoryString());
92     }
93   }
94 
getHistoryType()95   int getHistoryType() override {
96     if (m_undos.empty())
97       return TUndo::getHistoryType();
98     else
99       return m_undos.back()->getHistoryType();
100   }
101 };
102 }  // namespace
103 
104 typedef std::deque<TUndo *> UndoList;
105 typedef UndoList::iterator UndoListIterator;
106 typedef UndoList::const_iterator UndoListConstIterator;
107 
108 //-----------------------------------------------------------------------------
109 
110 struct TUndoManager::TUndoManagerImp {
111   UndoList m_undoList;
112   UndoListIterator m_current;
113   bool m_skipped;
114   int m_undoMemorySize;  // in bytes
115 
116   std::vector<TUndoBlock *> m_blockStack;
117 
118 public:
TUndoManagerImpTUndoManager::TUndoManagerImp119   TUndoManagerImp() : m_skipped(false), m_undoMemorySize(0) {
120     m_current = m_undoList.end();
121   }
~TUndoManagerImpTUndoManager::TUndoManagerImp122   ~TUndoManagerImp() {}
123 
124   void add(TUndo *undo);
125 
126 public:
127   static struct ManagerPtr {
128     TUndoManager *m_ptr;
129 
130   public:
ManagerPtrTUndoManager::TUndoManagerImp::ManagerPtr131     ManagerPtr() : m_ptr(0) {}
~ManagerPtrTUndoManager::TUndoManagerImp::ManagerPtr132     ~ManagerPtr() {
133       if (m_ptr) delete m_ptr;
134       m_ptr = 0;
135     }
136 
137   } theManager;
138 
139 private:
140   void doAdd(TUndo *undo);
141 };
142 
143 //=============================================================================
144 
145 TUndoManager::TUndoManagerImp::ManagerPtr
146     TUndoManager::TUndoManagerImp::theManager;
147 
148 //-----------------------------------------------------------------------------
149 
manager()150 TUndoManager *TUndoManager::manager() {
151   if (!TUndoManagerImp::theManager.m_ptr)
152     TUndoManagerImp::theManager.m_ptr = new TUndoManager;
153   return TUndoManagerImp::theManager.m_ptr;
154 }
155 
156 //=============================================================================
157 
TUndoManager()158 TUndoManager::TUndoManager() : m_imp(new TUndoManagerImp) {}
159 
160 //-----------------------------------------------------------------------------
161 
~TUndoManager()162 TUndoManager::~TUndoManager() {
163   // cout << "Distrutto undo manager" << endl;
164   assert(m_imp->m_blockStack.empty());
165   reset();
166 }
167 
168 //-----------------------------------------------------------------------------
169 
add(TUndo * undo)170 void TUndoManager::TUndoManagerImp::add(TUndo *undo) {
171   assert(undo);
172 
173   if (!m_blockStack.empty()) {
174     assert(m_current == m_undoList.end());
175     m_blockStack.back()->add(undo);
176   } else
177     doAdd(undo);
178 }
179 
180 //-----------------------------------------------------------------------------
181 
doAdd(TUndo * undo)182 void TUndoManager::TUndoManagerImp::doAdd(TUndo *undo) {
183   if (m_current != m_undoList.end()) {
184     std::for_each(m_current, m_undoList.end(), deleteUndo);
185     m_undoList.erase(m_current, m_undoList.end());
186   }
187 
188   int i, memorySize = 0, count = m_undoList.size();
189   for (i = 0; i < count; i++) memorySize += m_undoList[i]->getSize();
190 
191   while (count > 100 || (count != 0 && memorySize + undo->getSize() >
192                                            m_undoMemorySize))  // 20MB
193   {
194     --count;
195     TUndo *undo = m_undoList.front();
196     m_undoList.pop_front();
197     memorySize -= undo->getSize();
198     delete undo;
199   }
200 
201   undo->m_isLastInBlock     = true;
202   undo->m_isLastInRedoBlock = true;
203   m_undoList.push_back(undo);
204   m_current = m_undoList.end();
205 }
206 
207 //-----------------------------------------------------------------------------
208 
beginBlock()209 void TUndoManager::beginBlock() {
210   if (m_imp->m_current != m_imp->m_undoList.end()) {
211     std::for_each(m_imp->m_current, m_imp->m_undoList.end(), deleteUndo);
212     m_imp->m_undoList.erase(m_imp->m_current, m_imp->m_undoList.end());
213   }
214 
215   TUndoBlock *undoBlock = new TUndoBlock;
216   m_imp->m_blockStack.push_back(undoBlock);
217   m_imp->m_current = m_imp->m_undoList.end();
218 }
219 
220 //-----------------------------------------------------------------------------
221 
endBlock()222 void TUndoManager::endBlock() {
223   // vogliamo fare anche resize del vector ???
224   assert(m_imp->m_blockStack.empty() == false);
225   TUndoBlock *undoBlock = m_imp->m_blockStack.back();
226   m_imp->m_blockStack.pop_back();
227   if (undoBlock->getUndoCount() > 0) {
228     undoBlock->setLast();
229     m_imp->add(undoBlock);
230     emit historyChanged();
231   } else {
232     delete undoBlock;
233     m_imp->m_current = m_imp->m_undoList.end();
234   }
235 }
236 
237 //-----------------------------------------------------------------------------
238 
undo()239 bool TUndoManager::undo() {
240   assert(m_imp->m_blockStack.empty());
241   UndoListIterator &it = m_imp->m_current;
242   if (it != m_imp->m_undoList.begin()) {
243     m_imp->m_skipped = false;
244     --it;
245     (*it)->undo();
246     emit historyChanged();
247     if (m_imp->m_skipped) {
248       m_imp->m_skipped = false;
249       return undo();
250     }
251     return true;
252   } else
253     return false;
254 }
255 
256 //-----------------------------------------------------------------------------
257 
redo()258 bool TUndoManager::redo() {
259   assert(m_imp->m_blockStack.empty());
260   UndoListIterator &it = m_imp->m_current;
261   if (it != m_imp->m_undoList.end()) {
262     m_imp->m_skipped = false;
263     (*it)->redo();
264     ++it;
265     emit historyChanged();
266     if (m_imp->m_skipped) {
267       m_imp->m_skipped = false;
268       return redo();
269     }
270     return true;
271   } else
272     return false;
273 }
274 
275 //-----------------------------------------------------------------------------
276 // repeat e' come redo ma non sposta il puntatore al corrente
277 /*
278 void TUndoManager::repeat()
279 {
280   assert(m_imp->m_blockStack.empty());
281   UndoListIterator &it = m_imp->m_current;
282   if (it != m_imp->m_undoList.end())
283   {
284     (*it)->repeat();
285   }
286 }
287 */
288 
289 //-----------------------------------------------------------------------------
290 
skip()291 void TUndoManager::skip() { m_imp->m_skipped = true; }
292 
293 //-----------------------------------------------------------------------------
294 
setUndoMemorySize(int memorySyze)295 void TUndoManager::setUndoMemorySize(int memorySyze) {
296   m_imp->m_undoMemorySize = 1048576 * memorySyze;
297 }
298 
299 //-----------------------------------------------------------------------------
300 
add(TUndo * undo)301 void TUndoManager::add(TUndo *undo) {
302   assert(undo);
303   if (!undo) return;
304 
305   m_imp->add(undo);
306   Q_EMIT historyChanged();
307 
308   undo->onAdd();
309   Q_EMIT somethingChanged();
310 }
311 
312 //-----------------------------------------------------------------------------
313 
reset()314 void TUndoManager::reset() {
315   assert(m_imp->m_blockStack.empty());
316   m_imp->m_blockStack.clear();
317   UndoList &lst = m_imp->m_undoList;
318   std::for_each(lst.begin(), lst.end(), deleteUndo);
319   lst.clear();
320   m_imp->m_current = m_imp->m_undoList.end();
321   Q_EMIT historyChanged();
322 }
323 
324 //-----------------------------------------------------------------------------
325 
popUndo(int n,bool forward)326 void TUndoManager::popUndo(int n, bool forward) {
327   if (!forward) {
328     if (m_imp->m_blockStack.empty()) {
329       if (n == -1) {
330         UndoListIterator start = m_imp->m_undoList.begin();
331         n                      = 0;
332         while (start != m_imp->m_current) ++n;
333       }
334       if (m_imp->m_undoList.empty() || n <= 0) return;
335       if (m_imp->m_current == m_imp->m_undoList.end()) {
336         int i;
337         for (i = 0; i < n && m_imp->m_current != m_imp->m_undoList.begin();
338              i++) {
339           m_imp->m_current--;
340           delete (*m_imp->m_current);
341           m_imp->m_undoList.erase(m_imp->m_current);
342           m_imp->m_current = m_imp->m_undoList.end();
343         }
344       } else {
345         TUndo *undo = *m_imp->m_current;
346         UndoListIterator start, end = m_imp->m_current;
347         if (end == m_imp->m_undoList.begin()) return;
348 
349         int i;
350         for (i = 0; i < n && m_imp->m_current != m_imp->m_undoList.begin(); i++)
351           m_imp->m_current--;
352 
353         start                 = m_imp->m_current;
354         UndoListIterator _end = end;
355         while (_end != start) {
356           _end--;
357           delete (*_end);
358         }
359         m_imp->m_undoList.erase(start, end);
360 
361         m_imp->m_current = m_imp->m_undoList.begin();
362         while (*m_imp->m_current != undo) m_imp->m_current++;
363       }
364     } else
365       m_imp->m_blockStack.back()->popUndo(n);
366     return;
367   }
368 
369   if (m_imp->m_current == m_imp->m_undoList.end()) return;
370   if (m_imp->m_blockStack.empty()) {
371     UndoListIterator end, start = m_imp->m_current++;
372     if (n == -1)
373       end = m_imp->m_undoList.end();
374     else {
375       UndoListIterator it = start;
376       end                 = it;
377       int i               = 0;
378       while (i != n && end != m_imp->m_undoList.end()) {
379         ++end;
380         i++;
381       }
382     }
383     std::for_each(start, end, deleteUndo);
384     m_imp->m_undoList.erase(start, end);
385     m_imp->m_current = m_imp->m_undoList.end();
386   } else
387     m_imp->m_blockStack.back()->popUndo(n);
388 }
389 
390 //-----------------------------------------------------------------------------
391 
getHistoryCount()392 int TUndoManager::getHistoryCount() { return (int)m_imp->m_undoList.size(); }
393 
394 //-----------------------------------------------------------------------------
395 
getCurrentHistoryIndex()396 int TUndoManager::getCurrentHistoryIndex() {
397   int index           = 0;
398   UndoListIterator it = m_imp->m_undoList.begin();
399   while (1) {
400     if (it == m_imp->m_current) return index;
401 
402     if (it == m_imp->m_undoList.end()) break;
403 
404     index++;
405     it++;
406   }
407   return 0;
408 }
409 
410 //-----------------------------------------------------------------------------
411 
getUndoItem(int index)412 TUndo *TUndoManager::getUndoItem(int index) {
413   if (index > (int)m_imp->m_undoList.size() || index <= 0) return 0;
414 
415   return m_imp->m_undoList.at(index - 1);
416 }
417