1 /*
2 This file is a part of
3 QVGE - Qt Visual Graph Editor
4 
5 (c) 2016-2020 Ars L. Masiuk (ars.masiuk@gmail.com)
6 
7 It can be used freely, maintaining the information above.
8 */
9 
10 
11 #include "CDiffUndoManager.h"
12 #include "CEditorScene.h"
13 
14 #include <QDataStream>
15 
16 
CDiffUndoManager(CEditorScene & scene)17 CDiffUndoManager::CDiffUndoManager(CEditorScene & scene)
18     : m_scene(&scene)
19 {
20 }
21 
reset()22 void CDiffUndoManager::reset()
23 {
24 	m_redoStack.clear();
25 	m_undoStack.clear();
26 	m_redoStackTemp.clear();
27 	m_undoStackTemp.clear();
28 	m_lastState.clear();
29 }
30 
addState()31 void CDiffUndoManager::addState()
32 {
33 	// drop temp stacks
34 	m_redoStack.clear();
35 	m_undoStackTemp.clear();
36 
37 	// serialize & compress
38 	QByteArray snap;
39 	QDataStream ds(&snap, QIODevice::WriteOnly);
40 	m_scene->storeTo(ds, true);
41 
42 	// check if 1st store
43 	if (m_lastState.isEmpty() && m_undoStack.isEmpty() && m_redoStack.isEmpty())
44 	{
45 		m_lastState = snap;
46 		return;
47 	}
48 
49 	// push states into stacks
50 	int leftDiffIndex = 0;
51 	int len = qMin(snap.size(), m_lastState.size());
52 	while (leftDiffIndex < len && snap[leftDiffIndex] == m_lastState[leftDiffIndex])
53 		++leftDiffIndex;
54 
55 	int rightDiffIndex1 = m_lastState.size() - 1;
56 	int rightDiffIndex2 = snap.size() - 1;
57 	while (rightDiffIndex1 >= 0 && rightDiffIndex2 >= 0
58 		&& rightDiffIndex1 > leftDiffIndex && rightDiffIndex2 > leftDiffIndex
59 		&& snap[rightDiffIndex2] == m_lastState[rightDiffIndex1])
60 			--rightDiffIndex1, --rightDiffIndex2;
61 
62 	int len1 = rightDiffIndex1 - leftDiffIndex + 1;
63 	int len2 = rightDiffIndex2 - leftDiffIndex + 1;
64 
65 	Command cUndo = { leftDiffIndex, len2, qCompress(m_lastState.mid(leftDiffIndex, len1)) };
66 	Command cRedo = { leftDiffIndex, len1, qCompress(snap.mid(leftDiffIndex, len2)) };
67 
68 	m_undoStack << cUndo;
69 	m_redoStackTemp << cRedo;
70 
71 	// write last state
72 	m_lastState = snap;
73 }
74 
revertState()75 void CDiffUndoManager::revertState()
76 {
77 	QDataStream ds(&m_lastState, QIODevice::ReadOnly);
78 	m_scene->restoreFrom(ds, true);
79 }
80 
undo()81 void CDiffUndoManager::undo()
82 {
83 	if (availableUndoCount())
84 	{
85 		Command cUndo = m_undoStack.takeLast();
86 		m_lastState.replace(cUndo.index, cUndo.sizeToReplace, qUncompress(cUndo.data));
87 		QDataStream ds(&m_lastState, QIODevice::ReadOnly);
88 		m_scene->restoreFrom(ds, true);
89 
90 		m_redoStack << m_redoStackTemp.takeLast();
91 		m_undoStackTemp << cUndo;
92 	}
93 }
94 
redo()95 void CDiffUndoManager::redo()
96 {
97 	if (availableRedoCount())
98 	{
99 		Command cRedo = m_redoStack.takeLast();
100 		m_lastState.replace(cRedo.index, cRedo.sizeToReplace, qUncompress(cRedo.data));
101 		QDataStream ds(&m_lastState, QIODevice::ReadOnly);
102 		m_scene->restoreFrom(ds, true);
103 
104 		m_undoStack << m_undoStackTemp.takeLast();
105 		m_redoStackTemp << cRedo;
106 	}
107 }
108 
availableUndoCount() const109 int CDiffUndoManager::availableUndoCount() const
110 {
111 	return m_undoStack.size();
112 }
113 
availableRedoCount() const114 int CDiffUndoManager::availableRedoCount() const
115 {
116 	return m_redoStack.size();
117 }
118