annotate widgets/CommandHistory.h @ 854:c17719e488c9

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