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