diff data/model/EventCommands.h @ 1648:86bbccb79c9b single-point

Switch to a single external set of commands for modifying editables with events
author Chris Cannam
date Fri, 15 Mar 2019 10:57:35 +0000
parents
children 9d82b164f264
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/model/EventCommands.h	Fri Mar 15 10:57:35 2019 +0000
@@ -0,0 +1,140 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    This file copyright 2006 Chris Cannam.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef SV_EVENT_COMMANDS_H
+#define SV_EVENT_COMMANDS_H
+
+#include "base/Event.h"
+#include "base/Command.h"
+
+/**
+ * Interface for classes that can be modified through these commands
+ */
+class EventEditable
+{
+public:
+    virtual void add(Event e) = 0;
+    virtual void remove(Event e) = 0;
+};
+
+/**
+ * Command to add an event to an editable containing events, with undo.
+ */
+class AddEventCommand : public Command
+{
+public:
+    AddEventCommand(EventEditable *editable, const Event &e, QString name) :
+        m_editable(editable), m_event(e), m_name(name) { }
+
+    QString getName() const override { return m_name; }
+    Event getEvent() const { return m_event; }
+
+    void execute() override { m_editable->add(m_event); }
+    void unexecute() override { m_editable->remove(m_event); }
+
+private:
+    EventEditable *m_editable;
+    Event m_event;
+    QString m_name;
+};
+
+/**
+ * Command to remove an event from an editable containing events, with
+ * undo.
+ */
+class RemoveEventCommand : public Command
+{
+public:
+    RemoveEventCommand(EventEditable *editable, const Event &e, QString name) :
+        m_editable(editable), m_event(e), m_name(name) { }
+
+    QString getName() const override { return m_name; }
+    Event getEvent() const { return m_event; }
+
+    void execute() override { m_editable->remove(m_event); }
+    void unexecute() override { m_editable->add(m_event); }
+
+private:
+    EventEditable *m_editable;
+    Event m_event;
+    QString m_name;
+};
+
+/**
+ * Command to add or remove a series of events to or from an editable,
+ * with undo. Creates and immediately executes a sub-command for each
+ * add/remove requested. Consecutive add/remove pairs for the same
+ * point are collapsed.
+ */
+class ChangeEventsCommand : public MacroCommand
+{
+public:
+    ChangeEventsCommand(EventEditable *editable, QString name) :
+        MacroCommand(name), m_editable(editable) { }
+
+    void add(Event e) {
+        addCommand(new AddEventCommand(m_editable, e, getName()), true);
+    }
+    void remove(Event e) {
+        addCommand(new RemoveEventCommand(m_editable, e, getName()), true);
+    }
+
+    /**
+     * Stack an arbitrary other command in the same sequence.
+     */
+    void addCommand(Command *command) override { addCommand(command, true); }
+
+    /**
+     * If any points have been added or deleted, return this
+     * command (so the caller can add it to the command history).
+     * Otherwise delete the command and return NULL.
+     */
+    ChangeEventsCommand *finish() {
+        if (!m_commands.empty()) {
+            return this;
+        } else {
+            delete this;
+            return nullptr;
+        }
+    }
+
+protected:
+    virtual void addCommand(Command *command, bool executeFirst) {
+        
+        if (executeFirst) command->execute();
+
+        if (m_commands.empty()) {
+            MacroCommand::addCommand(command);
+            return;
+        }
+        
+        RemoveEventCommand *r =
+            dynamic_cast<RemoveEventCommand *>(command);
+        AddEventCommand *a =
+            dynamic_cast<AddEventCommand *>(*m_commands.rbegin());
+        if (r && a) {
+            if (a->getEvent() == r->getEvent()) {
+                deleteCommand(a);
+                return;
+            }
+        }
+        
+        MacroCommand::addCommand(command);
+    }
+
+    EventEditable *m_editable;
+};
+
+#endif