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

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 #include "command.h"
0022 #include "../filenamevisitor.h"
0023 #include "undoredoobserver.h"
0024 
0025 #include <list>
0026 #include <stdint.h>
0027 
0028 // help out Eclipse's C++ parsing
0029 #ifndef INT32_MAX
0030 #define INT32_MAX 0x7FFFFFFF
0031 #endif
0032 
0033 /**
0034  * Command list, for example the Undo or Redo stack.
0035  */
0036 class CommandList {
0037     typedef std::list<Command*> clist;
0038     clist cs;
0039 public:
0040     /**
0041      * Construct a NullAdder on the stack to be able to use FillNull() to add
0042      * a command to the command list without the risk of an exception being
0043      * thrown.
0044      */
0045     class NullAdder {
0046         CommandList& cl;
0047         NullAdder(const NullAdder&);
0048         NullAdder& operator=(const NullAdder&);
0049     public:
0050         NullAdder(CommandList& c) : cl(c) {
0051             cl.cs.push_front(0);
0052         }
0053         ~NullAdder() {
0054             if (!cl.cs.front())
0055                 cl.cs.pop_front();
0056         }
0057     };
0058     friend class NullAdder;
0059     CommandList() {
0060     }
0061     ~CommandList() {
0062         clear();
0063     }
0064     /**
0065      * Removes all commands from the list
0066      */
0067     void clear() {
0068         for (clist::iterator i = cs.begin(); i != cs.end(); ++i) {
0069             delete *i;
0070         }
0071         cs.clear();
0072     }
0073     /**
0074      * Returns true if and only if the command list is empty.
0075      */
0076     bool empty() const {
0077         return cs.empty();
0078     }
0079     /**
0080      * Returns the command at the front of the list
0081      */
0082     Command& front() const {
0083         return *cs.front();
0084     }
0085     /**
0086      * Adds a command to the front of the list.
0087      */
0088     void push(Command& c) {
0089         cs.push_front(&c);
0090     }
0091     /**
0092      * Adds a command to the back of the list.
0093      */
0094     void add(Command& c) {
0095         cs.push_back(&c);
0096     }
0097     /**
0098      * Fills a previously-added null with c. There must be no calls to
0099      * Push, Pop, Splice or Clear in between the construction of NullAdder and
0100      * FillNull. Will not throw an exception.
0101      */
0102     void fillNull(Command& c) {
0103         cs.front() = &c;
0104     }
0105     /**
0106      * Splices in the commands from the list newCommands into the front of
0107      * the list. This function will not throw an exception. newCommands
0108      * will be empty after this call.
0109      */
0110     void splice(CommandList& newCommands) {
0111         cs.splice(cs.begin(), newCommands.cs);
0112     }
0113     /**
0114      * Calls v.Add(f) for each filename f referenced by the commands in the
0115      * list.
0116      */
0117     void accept(FileNameVisitor& v) const {
0118         for (clist::const_iterator i = cs.begin(); i != cs.end(); ++i) {
0119             (*i)->accept(v);
0120         }
0121     }
0122     /**
0123      * Returns true if there is exactly one command in the list, false
0124      * otherwise
0125      */
0126     bool singleton() const {
0127         return cs.size() == 1;
0128     }
0129     /**
0130      * Executes the command at the front (if it exists) and puts its inverse
0131      * onto the front of 'to'.
0132      * @param to The list to receive the inverse command.
0133      */
0134     void executeFront(CommandList& to);
0135 };
0136 
0137 void CommandList::executeFront(CommandList& to) {
0138     if (empty())
0139         return;
0140     NullAdder na(to);
0141     Command* c = cs.front();
0142     Command* inv = c->execute();
0143     to.fillNull(*inv);
0144     // remove command c, which should have been deleted or recycled by
0145     // execute()
0146     cs.pop_front();
0147 }
0148 
0149 FileNameVisitor::~FileNameVisitor() {
0150 }
0151 
0152 void FileNameVisitor::reportNewScene() {
0153 }
0154 
0155 Command::Command() {
0156 }
0157 
0158 Command::~Command() {
0159 }
0160 
0161 void Command::accept(FileNameVisitor&) const {
0162 }
0163 
0164 class CommandNull : public Command {
0165 public:
0166     Command* execute() {
0167         // a null command is its own inverse
0168         return this;
0169     }
0170 };
0171 
0172 Command* createNullCommand() {
0173     return new CommandNull;
0174 }
0175 
0176 CommandFactory::~CommandFactory() {
0177 }
0178 
0179 Parameters::~Parameters() {
0180 }
0181 
0182 int32_t Parameters::getHowMany() {
0183     return getInteger(1, INT32_MAX);
0184 }
0185 
0186 CommandHistory::CommandHistory() : past(0), future(0), observer(0),
0187         previousCanUndo(false), previousCanRedo(false) {
0188     past = new CommandList();
0189     future = new CommandList();
0190 }
0191 
0192 CommandHistory::~CommandHistory() {
0193     delete past;
0194     delete future;
0195 }
0196 
0197 bool CommandHistory::canUndo() const {
0198     return !past->empty();
0199 }
0200 
0201 bool CommandHistory::canRedo() const {
0202     return !future->empty();
0203 }
0204 
0205 void CommandHistory::undo() {
0206     past->executeFront(*future);
0207     notifyObserver();
0208 }
0209 
0210 void CommandHistory::redo() {
0211     future->executeFront(*past);
0212     notifyObserver();
0213 }
0214 
0215 void CommandHistory::execute(Command& c) {
0216     future->clear();
0217     future->push(c);
0218     redo();
0219     notifyObserver();
0220 }
0221 
0222 void CommandHistory::clear() {
0223     future->clear();
0224     past->clear();
0225     notifyObserver();
0226 }
0227 
0228 void CommandHistory::accept(FileNameVisitor& v) const {
0229     future->accept(v);
0230     past->accept(v);
0231 }
0232 
0233 void CommandHistory::setUndoRedoObserver(UndoRedoObserver* ob) {
0234     observer = ob;
0235 }
0236 
0237 void CommandHistory::notifyObserver() {
0238     bool cu = canUndo();
0239     if (cu != previousCanUndo) {
0240         previousCanUndo = cu;
0241         if (observer)
0242             observer->updateCanUndo(cu);
0243     }
0244     bool cr = canRedo();
0245     if (cr != previousCanRedo) {
0246         previousCanRedo = cr;
0247         if (observer)
0248             observer->updateCanRedo(cr);
0249     }
0250 }