lbajardsilogic@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: Sonic Visualiser lbajardsilogic@0: An audio file viewer and annotation editor. lbajardsilogic@0: Centre for Digital Music, Queen Mary, University of London. lbajardsilogic@0: lbajardsilogic@0: This program is free software; you can redistribute it and/or lbajardsilogic@0: modify it under the terms of the GNU General Public License as lbajardsilogic@0: published by the Free Software Foundation; either version 2 of the lbajardsilogic@0: License, or (at your option) any later version. See the file lbajardsilogic@0: COPYING included with this distribution for more information. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: This is a modified version of a source file from the Rosegarden lbajardsilogic@0: MIDI and audio sequencer and notation editor, copyright 2000-2006 lbajardsilogic@0: Chris Cannam, distributed under the GNU General Public License. lbajardsilogic@0: lbajardsilogic@0: This file contains traces of the KCommandHistory class from the KDE lbajardsilogic@0: project, copyright 2000 Werner Trobin and David Faure and lbajardsilogic@0: distributed under the GNU Lesser General Public License. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: #ifndef _MULTI_VIEW_COMMAND_HISTORY_H_ lbajardsilogic@0: #define _MULTI_VIEW_COMMAND_HISTORY_H_ lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: class Command; lbajardsilogic@0: class MacroCommand; lbajardsilogic@0: class QAction; lbajardsilogic@0: class QMenu; lbajardsilogic@0: class QToolBar; lbajardsilogic@0: class QTimer; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * The CommandHistory class stores a list of executed commands and lbajardsilogic@0: * maintains Undo and Redo actions synchronised with those commands. lbajardsilogic@0: * lbajardsilogic@0: * CommandHistory allows you to associate more than one Undo and Redo lbajardsilogic@0: * menu or toolbar with the same command history, and it keeps them lbajardsilogic@0: * all up-to-date at once. This makes it effective in systems where lbajardsilogic@0: * multiple views may be editing the same data. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: class CommandHistory : public QObject lbajardsilogic@0: { lbajardsilogic@0: Q_OBJECT lbajardsilogic@0: lbajardsilogic@0: public: lbajardsilogic@0: virtual ~CommandHistory(); lbajardsilogic@0: lbajardsilogic@0: static CommandHistory *getInstance(); lbajardsilogic@0: lbajardsilogic@0: void clear(); lbajardsilogic@0: lbajardsilogic@0: void registerMenu(QMenu *menu); lbajardsilogic@0: void registerToolbar(QToolBar *toolbar); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Add a command to the command history. lbajardsilogic@0: * lbajardsilogic@0: * The command will normally be executed before being added; but lbajardsilogic@0: * if a compound operation is in use (see startCompoundOperation lbajardsilogic@0: * below), the execute status of the compound operation will lbajardsilogic@0: * determine whether the command is executed or not. lbajardsilogic@0: */ lbajardsilogic@0: void addCommand(Command *command); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Add a command to the command history. lbajardsilogic@0: * lbajardsilogic@0: * If execute is true, the command will be executed before being lbajardsilogic@0: * added. Otherwise it will be assumed to have been already lbajardsilogic@0: * executed -- a command should not be added to the history unless lbajardsilogic@0: * its work has actually been done somehow! lbajardsilogic@0: * lbajardsilogic@0: * If a compound operation is in use (see startCompoundOperation lbajardsilogic@0: * below), the execute value passed to this method will override lbajardsilogic@0: * the execute status of the compound operation. In this way it's lbajardsilogic@0: * possible to have a compound operation mixing both to-execute lbajardsilogic@0: * and pre-executed commands. lbajardsilogic@0: * lbajardsilogic@0: * If bundle is true, the command will be a candidate for bundling lbajardsilogic@0: * with any adjacent bundeable commands that have the same name, lbajardsilogic@0: * into a single compound command. This is useful for small lbajardsilogic@0: * commands that may be executed repeatedly altering the same data lbajardsilogic@0: * (e.g. type text, set a parameter) whose number and extent is lbajardsilogic@0: * not known in advance. The bundle parameter will be ignored if lbajardsilogic@0: * a compound operation is already in use. lbajardsilogic@0: */ lbajardsilogic@0: void addCommand(Command *command, bool execute, bool bundle = false); lbajardsilogic@0: lbajardsilogic@0: /// Return the maximum number of items in the undo history. lbajardsilogic@0: int getUndoLimit() const { return m_undoLimit; } lbajardsilogic@0: lbajardsilogic@0: /// Set the maximum number of items in the undo history. lbajardsilogic@0: void setUndoLimit(int limit); lbajardsilogic@0: lbajardsilogic@0: /// Return the maximum number of items in the redo history. lbajardsilogic@0: int getRedoLimit() const { return m_redoLimit; } lbajardsilogic@0: lbajardsilogic@0: /// Set the maximum number of items in the redo history. lbajardsilogic@0: void setRedoLimit(int limit); lbajardsilogic@0: lbajardsilogic@0: /// Return the maximum number of items visible in undo and redo menus. lbajardsilogic@0: int getMenuLimit() const { return m_menuLimit; } lbajardsilogic@0: lbajardsilogic@0: /// Set the maximum number of items in the menus. lbajardsilogic@0: void setMenuLimit(int limit); lbajardsilogic@0: lbajardsilogic@0: /// Return the time after which a bundle will be closed if nothing is added. lbajardsilogic@0: int getBundleTimeout() const { return m_bundleTimeout; } lbajardsilogic@0: lbajardsilogic@0: /// Set the time after which a bundle will be closed if nothing is added. lbajardsilogic@0: void setBundleTimeout(int msec); lbajardsilogic@0: lbajardsilogic@0: /// Start recording commands to batch up into a single compound command. lbajardsilogic@0: void startCompoundOperation(QString name, bool execute); lbajardsilogic@0: lbajardsilogic@0: /// Finish recording commands and store the compound command. lbajardsilogic@0: void endCompoundOperation(); lbajardsilogic@0: lbajardsilogic@0: public slots: lbajardsilogic@0: /** lbajardsilogic@0: * Checkpoint function that should be called when the document is lbajardsilogic@0: * saved. If the undo/redo stack later returns to the point at lbajardsilogic@0: * which the document was saved, the documentRestored signal will lbajardsilogic@0: * be emitted. lbajardsilogic@0: */ lbajardsilogic@0: virtual void documentSaved(); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Add a command to the history that has already been executed, lbajardsilogic@0: * without executing it again. Equivalent to addCommand(command, false). lbajardsilogic@0: */ lbajardsilogic@0: void addExecutedCommand(Command *); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Add a command to the history and also execute it. Equivalent lbajardsilogic@0: * to addCommand(command, true). lbajardsilogic@0: */ lbajardsilogic@0: void addCommandAndExecute(Command *); lbajardsilogic@0: lbajardsilogic@0: void undo(); lbajardsilogic@0: void redo(); lbajardsilogic@0: lbajardsilogic@0: protected slots: lbajardsilogic@0: void undoActivated(QAction *); lbajardsilogic@0: void redoActivated(QAction *); lbajardsilogic@0: void bundleTimerTimeout(); lbajardsilogic@0: lbajardsilogic@0: signals: lbajardsilogic@0: /** lbajardsilogic@0: * Emitted whenever a command has just been executed or lbajardsilogic@0: * unexecuted, whether by addCommand, undo, or redo. lbajardsilogic@0: */ lbajardsilogic@0: void commandExecuted(); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Emitted whenever a command has just been executed, whether by lbajardsilogic@0: * addCommand or redo. lbajardsilogic@0: */ lbajardsilogic@0: void commandExecuted(Command *); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Emitted whenever a command has just been unexecuted, whether by lbajardsilogic@0: * addCommand or undo. lbajardsilogic@0: */ lbajardsilogic@0: void commandUnexecuted(Command *); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Emitted when the undo/redo stack has reached the same state at lbajardsilogic@0: * which the documentSaved slot was last called. lbajardsilogic@0: */ lbajardsilogic@0: void documentRestored(); lbajardsilogic@0: lbajardsilogic@0: protected: lbajardsilogic@0: CommandHistory(); lbajardsilogic@0: static CommandHistory *m_instance; lbajardsilogic@0: lbajardsilogic@0: QAction *m_undoAction; lbajardsilogic@0: QAction *m_redoAction; lbajardsilogic@0: QAction *m_undoMenuAction; lbajardsilogic@0: QAction *m_redoMenuAction; lbajardsilogic@0: QMenu *m_undoMenu; lbajardsilogic@0: QMenu *m_redoMenu; lbajardsilogic@0: lbajardsilogic@0: std::map m_actionCounts; lbajardsilogic@0: lbajardsilogic@0: typedef std::stack CommandStack; lbajardsilogic@0: CommandStack m_undoStack; lbajardsilogic@0: CommandStack m_redoStack; lbajardsilogic@0: lbajardsilogic@0: int m_undoLimit; lbajardsilogic@0: int m_redoLimit; lbajardsilogic@0: int m_menuLimit; lbajardsilogic@0: int m_savedAt; lbajardsilogic@0: lbajardsilogic@0: MacroCommand *m_currentCompound; lbajardsilogic@0: bool m_executeCompound; lbajardsilogic@0: void addToCompound(Command *command, bool execute); lbajardsilogic@0: lbajardsilogic@0: MacroCommand *m_currentBundle; lbajardsilogic@0: QString m_currentBundleName; lbajardsilogic@0: QTimer *m_bundleTimer; lbajardsilogic@0: int m_bundleTimeout; lbajardsilogic@0: void addToBundle(Command *command, bool execute); lbajardsilogic@0: void closeBundle(); lbajardsilogic@0: lbajardsilogic@0: void updateActions(); lbajardsilogic@0: lbajardsilogic@0: void clipCommands(); lbajardsilogic@0: lbajardsilogic@0: void clipStack(CommandStack &stack, int limit); lbajardsilogic@0: void clearStack(CommandStack &stack); lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: #endif