1 /*
2    Drawpile - a collaborative drawing program.
3 
4    Copyright (C) 2013-2017 Calle Laakkonen
5 
6    Drawpile is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation, either version 3 of the License, or
9    (at your option) any later version.
10 
11    Drawpile is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with Drawpile.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 #ifndef DP_STATETRACKER_H
20 #define DP_STATETRACKER_H
21 
22 #include "retcon.h"
23 #include "history.h"
24 #include "../core/point.h"
25 
26 #include <QObject>
27 #include <QExplicitlySharedDataPointer>
28 
29 namespace protocol {
30 	class CanvasResize;
31 	class CanvasBackground;
32 	class LayerCreate;
33 	class LayerAttributes;
34 	class LayerVisibility;
35 	class LayerRetitle;
36 	class LayerOrder;
37 	class LayerDelete;
38 	class DefaultLayer;
39 	class ToolChange;
40 	class PenMove;
41 	class PenUp;
42 	class DrawDabsClassic;
43 	class DrawDabsPixel;
44 	class PutImage;
45 	class PutTile;
46 	class FillRect;
47 	class UndoPoint;
48 	class Undo;
49 	class AnnotationCreate;
50 	class AnnotationReshape;
51 	class AnnotationEdit;
52 	class AnnotationDelete;
53 	class MoveRegion;
54 }
55 
56 namespace paintcore {
57 	class LayerStack;
58 	struct Savepoint;
59 }
60 
61 class QTimer;
62 
63 namespace canvas {
64 
65 class StateTracker;
66 class CanvasModel;
67 
68 /**
69  * @brief A snapshot of the statetracker state.
70  *
71  * This is used for undo/redo as well as jumping around in indexed recordings.
72  */
73 class StateSavepoint {
74 public:
75 	struct Data;
76 
77 	StateSavepoint();
78 	StateSavepoint(Data *d);
79 	StateSavepoint(const StateSavepoint &other);
80 	~StateSavepoint();
81 
82 	StateSavepoint &operator=(const StateSavepoint &other);
83 
84 	operator bool() const { return d; }
85 	bool operator!() const { return !d; }
86 	bool operator==(const StateSavepoint &sp) const { return d == sp.d; }
87 	bool operator!=(const StateSavepoint &sp) const { return d != sp.d; }
88 
89 	//! Get this snapshot's timestamp
90 	qint64 timestamp() const;
91 
92 	//! Get the canvas snapshot
93 	paintcore::Savepoint canvas() const;
94 
95 	/**
96 	 * @brief Get a thumbnail of savepoint content
97 	 * @param maxSize maximum thumbnail size
98 	 */
99 	QImage thumbnail(const QSize &maxSize) const;
100 
101 	/**
102 	 * @brief Generate a list of commands to initialize a session to this savepoint
103 	 *
104 	 * (Used when resetting a session to a prior state.)
105 	 *
106 	 * @param contextId context Id of the user resetting
107 	 * @param canvas if set, ACL settings are got from here
108 	 */
109 	protocol::MessageList initCommands(uint8_t contextId, const CanvasModel *canvas) const;
110 
111 	const Data *operator->() const { Q_ASSERT(d); return d.constData(); }
112 
113 	/**
114 	 * @brief Make a state savepoint from just a canvas savepoint
115 	 *
116 	 * This is used to create an savepoint from a serialized canvas state
117 	 * stored in an index.
118 	 *
119 	 * @param savepoint
120 	 */
121 	static StateSavepoint fromCanvasSavepoint(const paintcore::Savepoint &savepoint);
122 
123 private:
124 	QExplicitlySharedDataPointer<Data> d;
125 };
126 
127 }
128 
129 Q_DECLARE_TYPEINFO(canvas::StateSavepoint, Q_MOVABLE_TYPE);
130 
131 namespace canvas {
132 
133 class LayerListModel;
134 
135 /**
136  * \brief Drawing context state tracker
137  *
138  * The state tracker object keeps track of each drawing context and performs
139  * the drawing using the paint engine.
140  */
141 class StateTracker : public QObject {
142 	Q_OBJECT
143 public:
144 	StateTracker(paintcore::LayerStack *image, LayerListModel *layerlist, uint8_t myId, QObject *parent=nullptr);
145 	StateTracker(const StateTracker &) = delete;
146 	~StateTracker();
147 
148 	void localCommand(protocol::MessagePtr msg);
149 	void receiveCommand(protocol::MessagePtr msg);
150 	void receiveQueuedCommand(protocol::MessagePtr msg);
151 
152 	void endRemoteContexts();
153 	void endPlayback();
154 
155 	//! Reset the entire history
156 	void reset();
157 
158 	/**
159 	 * @brief Set if all user markers (own included) should be shown
160 	 * @param showall
161 	 */
setShowAllUserMarkers(bool showall)162 	void setShowAllUserMarkers(bool showall) { _showallmarkers = showall; }
163 
164 	/**
165 	 * @brief Get the local user's ID
166 	 * @return
167 	 */
localId()168 	uint8_t localId() const { return m_myId; }
169 
170 	/**
171 	 * @brief Set the local user's ID
172 	 */
setLocalId(uint8_t id)173 	void setLocalId(uint8_t id) { m_myId = id; }
174 
175 	/**
176 	 * @brief Get the paint canvas
177 	 * @return
178 	 */
image()179 	paintcore::LayerStack *image() const { return m_layerstack; }
180 
181 	//! Get the layer list model
layerList()182 	LayerListModel *layerList() const { return m_layerlist; }
183 
184 	//! Has the local user participated in the session yet?
hasParticipated()185 	bool hasParticipated() const { return m_hasParticipated; }
186 
187 	StateTracker &operator=(const StateTracker&) = delete;
188 
189 	/**
190 	 * @brief Create a new savepoint
191 	 *
192 	 * This is used internally for undo/redo as well as when
193 	 * saving snapshots for an indexed recording.
194 	 * @return
195 	 */
196 	StateSavepoint createSavepoint(int pos);
197 
198 	/**
199 	 * @brief Reset state to the given save point
200 	 *
201 	 * This is used when jumping inside a recording. Calling this
202 	 * will reset session history
203 	 * @param sp
204 	 */
205 	void resetToSavepoint(StateSavepoint sp);
206 
207 	//! Get all existing reset points (savepoints set aside for session resetting use)
getResetPoints()208 	QList<StateSavepoint> getResetPoints() const { return m_resetpoints; }
209 
210 signals:
211 	void myAnnotationCreated(int id);
212 	void layerAutoselectRequest(int);
213 
214 	void userMarkerMove(int id, int layerId, const QPoint &point);
215 	void userMarkerHide(int id);
216 
217 	void catchupProgress(int percent);
218 	void sequencePoint(int);
219 
220 	void softResetPoint();
221 
222 public slots:
223 	void previewLayerOpacity(int id, float opacity);
224 
225 	/**
226 	 * @brief Set the "local user is currently drawing!" hint
227 	 *
228 	 * This affects the way the retcon local fork is handled: when
229 	 * local drawing is in progress, the local fork is not discarded
230 	 * on conflict (with other users) to avoid self-conflict feedback loop.
231 	 *
232 	 * Not setting this flag doesn't break anything, but may cause
233 	 * unnecessary rollbacks if a conflict occurs during local drawing.
234 	 */
setLocalDrawingInProgress(bool pendown)235 	void setLocalDrawingInProgress(bool pendown) { m_localPenDown = pendown; }
236 
237 private slots:
238 	void processQueuedCommands();
239 
240 private:
241 	void handleCommand(protocol::MessagePtr msg, bool replay, int pos);
242 
243 	AffectedArea affectedArea(const protocol::MessagePtr msg) const;
244 
245 	// Layer related commands
246 	void handleCanvasResize(const protocol::CanvasResize &cmd, int pos);
247 	void handleCanvasBackground(const protocol::CanvasBackground &cmd);
248 	void handleLayerCreate(const protocol::LayerCreate &cmd);
249 	void handleLayerAttributes(const protocol::LayerAttributes &cmd);
250 	void handleLayerVisibility(const protocol::LayerVisibility &cmd);
251 	void handleLayerTitle(const protocol::LayerRetitle &cmd);
252 	void handleLayerOrder(const protocol::LayerOrder &cmd);
253 	void handleLayerDelete(const protocol::LayerDelete &cmd);
254 	void handleLayerDefault(const protocol::DefaultLayer &cmd);
255 
256 	// Drawing related commands
257 	void handleDrawDabs(const protocol::Message &msg);
258 	void handlePenUp(const protocol::PenUp &cmd);
259 	void handlePutImage(const protocol::PutImage &cmd);
260 	void handlePutTile(const protocol::PutTile &cmd);
261 	void handleFillRect(const protocol::FillRect &cmd);
262 	void handleMoveRegion(const protocol::MoveRegion &cmd);
263 
264 	// Undo/redo
265 	void handleUndoPoint(const protocol::UndoPoint &cmd, bool replay, int pos);
266 	void handleUndo(protocol::Undo &cmd);
267 	void makeSavepoint(int pos);
268 	void revertSavepointAndReplay(const StateSavepoint savepoint);
269 	void handleTruncateHistory();
270 
271 	// Annotation related commands
272 	void handleAnnotationCreate(const protocol::AnnotationCreate &cmd);
273 	void handleAnnotationReshape(const protocol::AnnotationReshape &cmd);
274 	void handleAnnotationEdit(const protocol::AnnotationEdit &cmd);
275 	void handleAnnotationDelete(const protocol::AnnotationDelete &cmd);
276 
277 	paintcore::LayerStack *m_layerstack;
278 	LayerListModel *m_layerlist;
279 
280 	QString _title;
281 	uint8_t m_myId;
282 	int m_myLastLayer;
283 
284 	History m_history;
285 	QList<StateSavepoint> m_savepoints;
286 	QList<StateSavepoint> m_resetpoints;
287 
288 	LocalFork m_localfork;
289 
290 	bool _showallmarkers;
291 	bool m_hasParticipated;
292 	bool m_localPenDown;
293 
294 	protocol::MessageList m_msgqueue;
295 	QTimer *m_queuetimer;
296 	bool m_isQueued;
297 };
298 
299 }
300 
301 #endif
302