File indexing completed on 2024-05-12 16:23:28

0001 /***************************************************************************
0002  *   Copyright (C) 2013 by Linuxstopmotion contributors;                   *
0003  *   see the AUTHORS file for details.                                     *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; if not, write to the                         *
0017  *   Free Software Foundation, Inc.,                                       *
0018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
0019  ***************************************************************************/
0020 
0021 #ifndef EXECUTOR_H_
0022 #define EXECUTOR_H_
0023 
0024 #include <exception>
0025 #include <memory>
0026 
0027 /**
0028  * Thrown if a command factory attempts to read a parameter from the log files
0029  * that is of the wrong type, is not present or otherwise does not parse.
0030  */
0031 class IncorrectParameterException : public std::exception {
0032     const char* what() const throw();
0033 };
0034 
0035 /**
0036  * Thrown if a line from the log parses correctly but has extra unexpected
0037  * characters at its end.
0038  */
0039 class MalformedLineException : public std::exception {
0040     const char* what() const throw();
0041 };
0042 
0043 /**
0044  * Thrown if the parameters for a command (from the log or from a caller) are
0045  * inappropriate for the current state of the model.
0046  */
0047 class ParametersOutOfRangeException : public std::exception {
0048 public:
0049     ParametersOutOfRangeException() {
0050     }
0051     const char* what() const throw();
0052 };
0053 
0054 class CommandFactory;
0055 class CommandLogger;
0056 class ErrorHandler;
0057 class Parameters;
0058 class RandomSource;
0059 class UndoRedoObserver;
0060 
0061 /**
0062  * Thrown if @ref CommandFactory::Execute is called with a name for which no
0063  * command has been added, or if @ref CommandFactory::executeRandomCommands is
0064  * called on a @ref CommandFactory which has had no commands added, or if
0065  * @ref CommandFactory::executeRandomConstructiveCommands is called
0066  * on a @ref CommandFactory which has had no constructive commands set.
0067  */
0068 class UnknownCommandException : public std::exception {
0069     const char* what() const throw();
0070 };
0071 
0072 class CommandNameAlreadyUsedException : public std::exception {
0073     const char* what() const throw();
0074 };
0075 
0076 class Executor {
0077 public:
0078     virtual ~Executor() = 0;
0079     /**
0080      * Executes a command, logging it and putting its inverse onto the undo
0081      * stack. Be careful that the argument list exactly matches what the
0082      * command expects; in particular, all integers should be @c int32_t. If
0083      * you supply a command factory, you should also supply a wrapper for this
0084      * Execute function to make sure this is done correctly, for example:
0085      * @code{.cpp}
0086      * void ExecuteAddFrame(Executor& e, const char* filename, int32_t sceneNo,
0087      *     int32_t frameNo) {
0088      *   e.Execute("addf", filename, sceneNo, frameNo);
0089      * }
0090      * @endcode
0091      * @param name The name with which the command's factory was registered.
0092      */
0093     virtual void execute(const char* name, ...) = 0;
0094     /**
0095      * Executes a command, logging it and putting its inverse onto the undo
0096      * stack.
0097      * @param name The name with which the command's factory was registered.
0098      * @param params Supplier of the parameters to the command.
0099      */
0100     virtual void execute(const char* name, Parameters& params) = 0;
0101     /**
0102      * Executes the command described by (the first line of) @a line, a line
0103      * from a command log previously written by a call to @ref execute.
0104      * @param line Null- or line-ending-terminated string; a line from the log.
0105      * @return true if a command was executed, false if the line was empty or
0106      * contained only undo and redo instructions.
0107      * @throws MalformedLineException if the line is neither empty nor starts
0108      * with a command name.
0109      */
0110     virtual bool executeFromLog(const char* line, ErrorHandler& e) = 0;
0111     /**
0112      * Executes a random set of commands. Used for testing.
0113      * @param rng The random number generator.
0114      * @param min The minimum number of commands that should be generated.
0115      * @param max The maximum number of commands that should be generated.
0116      * @param [out] commandCount Returns the number of commands actually
0117      * executed, even if an exception is thrown.
0118      */
0119     virtual void executeRandomCommands(int& commandCount, RandomSource& rng,
0120             int min, int max) = 0;
0121     /**
0122      * Executes a random set of commands. Used for testing for constructing
0123      * fresh models from empty models. Only commands that were added with the
0124      * @a constructive parameter of @ref addCommand set to @c true are used.
0125      * @param rng The random number generator.
0126      */
0127     virtual void executeRandomConstructiveCommands(RandomSource& rng) = 0;
0128     /**
0129      * Make a command available for execution. It is assumed that @a name
0130      * endures for the lifetime of the Executor. Ideally name should be a
0131      * static constant, not heap allocated; for example
0132      * @code{.cpp}
0133      * executor.addCommand("addf", addFactory, true);
0134      * @endcode
0135      * @throws CommandNameAlreadyUsedException if a factory has already
0136      * been registered under @a name.
0137      * @param name The name of the command. Will need to be supplied in a
0138      * call to @ref Execute in order to use @a factory.
0139      * @param factory The factory that makes these sort of commands.
0140      * @param constructive If true is passed, test code will use this
0141      * factory to construct initial model states from empty models. Therefore
0142      * @c true should be passed whenever the command is useful in constructing
0143      * an initial state. For example, an add operation is constructive, but a
0144      * delete or a move is not.
0145      * @ref executeRandomConstructiveCommands uses only those factories
0146      * passed here with @a constructive set to @c true.
0147      */
0148     virtual void addCommand(const char* name,
0149             std::unique_ptr<CommandFactory>factory,
0150             bool constructive = false) = 0;
0151     /**
0152      * Sets the logger to be used to record commands executed.
0153      * @param logger The logger to be set. Ownership is not passed.
0154      * Pass NULL to get no logging.
0155      */
0156     virtual void setCommandLogger(CommandLogger* logger) = 0;
0157     /**
0158      * Clears the undo and redo stacks.
0159      */
0160     virtual void clearHistory() = 0;
0161     /**
0162      * Undoes the most recent command.
0163      * @return true on success, false if nothing was on the undo stack.
0164      */
0165     virtual bool undo() = 0;
0166     /**
0167      * Redoes the most recently undone command.
0168      * @return true on success, false if nothing was on the redo stack.
0169      */
0170     virtual bool redo() = 0;
0171     /**
0172      * Returns true if and only if there is a command waiting to be undone.
0173      */
0174     virtual bool canUndo() const = 0;
0175     /**
0176      * Returns true if and only if there is a command waiting to be redone.
0177      */
0178     virtual bool canRedo() const = 0;
0179     /**
0180      * The number of commands registered.
0181      * @par
0182      * Useful for determining how many randomized tests to run.
0183      */
0184     virtual int commandCount() const = 0;
0185     /**
0186      * Sets the observer to be notified when {@ref canUndo} or {@ref canRedo}
0187      * change what they would return.
0188      * @param observer The new observer to be set. The old observer is unset.
0189      * A null pointer means no observer. Ownership is not passed.
0190      */
0191     virtual void setUndoRedoObserver(UndoRedoObserver* observer) = 0;
0192 };
0193 
0194 /**
0195  * Create a new executor.
0196  * @return The new {@ref Executor}; ownership is returned.
0197  */
0198 Executor* makeExecutor();
0199 
0200 #endif /* EXECUTOR_H_ */