1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 2 3 /* 4 Sonic Visualiser 5 An audio file viewer and annotation editor. 6 Centre for Digital Music, Queen Mary, University of London. 7 8 This program is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License as 10 published by the Free Software Foundation; either version 2 of the 11 License, or (at your option) any later version. See the file 12 COPYING included with this distribution for more information. 13 */ 14 15 /* 16 This is a modified version of a source file from the Rosegarden 17 MIDI and audio sequencer and notation editor, copyright 2000-2006 18 Chris Cannam, distributed under the GNU General Public License. 19 20 This file contains traces of the KCommandHistory class from the KDE 21 project, copyright 2000 Werner Trobin and David Faure and 22 distributed under the GNU Lesser General Public License. 23 */ 24 25 #ifndef SV_MULTI_VIEW_COMMAND_HISTORY_H 26 #define SV_MULTI_VIEW_COMMAND_HISTORY_H 27 28 #include <QObject> 29 #include <QString> 30 31 #include <stack> 32 #include <set> 33 #include <map> 34 35 class Command; 36 class MacroCommand; 37 class QAction; 38 class QMenu; 39 class QToolBar; 40 class QTimer; 41 42 /** 43 * The CommandHistory class stores a list of executed commands and 44 * maintains Undo and Redo actions synchronised with those commands. 45 * 46 * CommandHistory allows you to associate more than one Undo and Redo 47 * menu or toolbar with the same command history, and it keeps them 48 * all up-to-date at once. This makes it effective in systems where 49 * multiple views may be editing the same data. 50 */ 51 52 class CommandHistory : public QObject 53 { 54 Q_OBJECT 55 56 public: 57 virtual ~CommandHistory(); 58 59 static CommandHistory *getInstance(); 60 61 void clear(); 62 63 void registerMenu(QMenu *menu); 64 void registerToolbar(QToolBar *toolbar); 65 66 /** 67 * Add a command to the command history. 68 * 69 * The command will normally be executed before being added; but 70 * if a compound operation is in use (see startCompoundOperation 71 * below), the execute status of the compound operation will 72 * determine whether the command is executed or not. 73 */ 74 void addCommand(Command *command); 75 76 /** 77 * Add a command to the command history. 78 * 79 * If execute is true, the command will be executed before being 80 * added. Otherwise it will be assumed to have been already 81 * executed -- a command should not be added to the history unless 82 * its work has actually been done somehow! 83 * 84 * If a compound operation is in use (see startCompoundOperation 85 * below), the execute value passed to this method will override 86 * the execute status of the compound operation. In this way it's 87 * possible to have a compound operation mixing both to-execute 88 * and pre-executed commands. 89 * 90 * If bundle is true, the command will be a candidate for bundling 91 * with any adjacent bundleable commands that have the same name, 92 * into a single compound command. This is useful for small 93 * commands that may be executed repeatedly altering the same data 94 * (e.g. type text, set a parameter) whose number and extent is 95 * not known in advance. The bundle parameter will be ignored if 96 * a compound operation is already in use. 97 */ 98 void addCommand(Command *command, bool execute, bool bundle = false); 99 100 /// Return the maximum number of items in the undo history. getUndoLimit()101 int getUndoLimit() const { return m_undoLimit; } 102 103 /// Set the maximum number of items in the undo history. 104 void setUndoLimit(int limit); 105 106 /// Return the maximum number of items in the redo history. getRedoLimit()107 int getRedoLimit() const { return m_redoLimit; } 108 109 /// Set the maximum number of items in the redo history. 110 void setRedoLimit(int limit); 111 112 /// Return the maximum number of items visible in undo and redo menus. getMenuLimit()113 int getMenuLimit() const { return m_menuLimit; } 114 115 /// Set the maximum number of items in the menus. 116 void setMenuLimit(int limit); 117 118 /// Return the time after which a bundle will be closed if nothing is added. getBundleTimeout()119 int getBundleTimeout() const { return m_bundleTimeout; } 120 121 /// Set the time after which a bundle will be closed if nothing is added. 122 void setBundleTimeout(int msec); 123 124 /// Start recording commands to batch up into a single compound command. 125 void startCompoundOperation(QString name, bool execute); 126 127 /// Finish recording commands and store the compound command. 128 void endCompoundOperation(); 129 130 public slots: 131 /** 132 * Checkpoint function that should be called when the document is 133 * saved. If the undo/redo stack later returns to the point at 134 * which the document was saved, the documentRestored signal will 135 * be emitted. 136 */ 137 virtual void documentSaved(); 138 139 /** 140 * Add a command to the history that has already been executed, 141 * without executing it again. Equivalent to addCommand(command, false). 142 */ 143 void addExecutedCommand(Command *); 144 145 /** 146 * Add a command to the history and also execute it. Equivalent 147 * to addCommand(command, true). 148 */ 149 void addCommandAndExecute(Command *); 150 151 void undo(); 152 void redo(); 153 154 protected slots: 155 void undoActivated(QAction *); 156 void redoActivated(QAction *); 157 void bundleTimerTimeout(); 158 159 signals: 160 /** 161 * Emitted whenever a command has just been executed or 162 * unexecuted, whether by addCommand, undo, or redo. 163 */ 164 void commandExecuted(); 165 166 /** 167 * Emitted whenever a command has just been executed, whether by 168 * addCommand or redo. 169 */ 170 void commandExecuted(Command *); 171 172 /** 173 * Emitted whenever a command has just been unexecuted, whether by 174 * addCommand or undo. 175 */ 176 void commandUnexecuted(Command *); 177 178 /** 179 * Emitted when the undo/redo stack has reached the same state at 180 * which the documentSaved slot was last called. 181 */ 182 void documentRestored(); 183 184 /** 185 * Emitted when some activity happened (for activity logging). 186 */ 187 void activity(QString); 188 189 protected: 190 CommandHistory(); 191 static CommandHistory *m_instance; 192 193 QAction *m_undoAction; 194 QAction *m_redoAction; 195 QAction *m_undoMenuAction; 196 QAction *m_redoMenuAction; 197 QMenu *m_undoMenu; 198 QMenu *m_redoMenu; 199 200 std::map<QAction *, int> m_actionCounts; 201 202 typedef std::stack<Command *> CommandStack; 203 CommandStack m_undoStack; 204 CommandStack m_redoStack; 205 206 int m_undoLimit; 207 int m_redoLimit; 208 int m_menuLimit; 209 int m_savedAt; 210 211 MacroCommand *m_currentCompound; 212 bool m_executeCompound; 213 void addToCompound(Command *command, bool execute); 214 215 MacroCommand *m_currentBundle; 216 bool m_bundling; 217 QString m_currentBundleName; 218 QTimer *m_bundleTimer; 219 int m_bundleTimeout; 220 void addToBundle(Command *command, bool execute); 221 void closeBundle(); 222 223 void updateActions(); 224 225 void clipCommands(); 226 227 void clipStack(CommandStack &stack, int limit); 228 void clearStack(CommandStack &stack); 229 }; 230 231 232 #endif 233