From 31c80c4e522c438809f6081248f090eee7199a64 Mon Sep 17 00:00:00 2001 From: Luis Gabriel Lima Date: Fri, 23 Mar 2012 10:21:23 -0300 Subject: Add Undo Framework QML API This commit introduces an initial implementation of a QML API for the Undo Framework. The QML plugin for this API exports three new QML elements: UndoStack, UndoCommand and UndoPropertyCommand. The API for both the first and the second are very similar to the QUndoStack and QUndoCommand C++ APIs. The thrid use the declarative nature of the QML elements to undo/redo based on the values of a group of properties specified by the user. This commit also adds an example in 'examples/undo/quickundo' to show how this API could be used. Other patchs are expected soon to improve this API and also add more examples/docs. Change-Id: I9d290f514b360c721116c3937bd0e03d5f0eacbb Reviewed-by: Anselmo L. S. Melo --- examples/undo/quickundo/Button.qml | 20 ++++ examples/undo/quickundo/main.qml | 74 ++++++++++++++ examples/undo/quickundo/quickundo.qmlproject | 16 +++ src/imports/imports.pro | 3 + src/imports/undo/plugin.cpp | 68 +++++++++++++ src/imports/undo/qmldir | 1 + src/imports/undo/uiquickundocommands.cpp | 147 +++++++++++++++++++++++++++ src/imports/undo/uiquickundocommands_p.h | 134 ++++++++++++++++++++++++ src/imports/undo/uiquickundostack.cpp | 100 ++++++++++++++++++ src/imports/undo/uiquickundostack_p.h | 84 +++++++++++++++ src/imports/undo/undo.pro | 24 +++++ uihelpers.pro | 4 + 12 files changed, 675 insertions(+) create mode 100644 examples/undo/quickundo/Button.qml create mode 100644 examples/undo/quickundo/main.qml create mode 100644 examples/undo/quickundo/quickundo.qmlproject create mode 100644 src/imports/imports.pro create mode 100644 src/imports/undo/plugin.cpp create mode 100644 src/imports/undo/qmldir create mode 100644 src/imports/undo/uiquickundocommands.cpp create mode 100644 src/imports/undo/uiquickundocommands_p.h create mode 100644 src/imports/undo/uiquickundostack.cpp create mode 100644 src/imports/undo/uiquickundostack_p.h create mode 100644 src/imports/undo/undo.pro diff --git a/examples/undo/quickundo/Button.qml b/examples/undo/quickundo/Button.qml new file mode 100644 index 0000000..6b1d9ec --- /dev/null +++ b/examples/undo/quickundo/Button.qml @@ -0,0 +1,20 @@ +import QtQuick 2.0 + +Rectangle { + id: root + property alias text: label.text + signal clicked() + + + width: 50 + height: 50 + Text { + id: label + anchors.centerIn: parent + } + + MouseArea { + anchors.fill: parent + onClicked: root.clicked() + } +} diff --git a/examples/undo/quickundo/main.qml b/examples/undo/quickundo/main.qml new file mode 100644 index 0000000..1b17c9a --- /dev/null +++ b/examples/undo/quickundo/main.qml @@ -0,0 +1,74 @@ +import QtQuick 2.0 +import Playground.UiHelpers.UndoFramework 1.0 + +Rectangle { + id: root + + width: 800 + height: 600 + + UndoStack { + id: stack + } + + UndoPropertyCommand { + id: moveCommand + properties: ["x", "y"] + } + + UndoCommand { + id: colorCommand + onUndo: target.color = Qt.rgba(0, 0, 0, 1); + onRedo: target.color = Qt.rgba(0.5, 0.2, 0.1, 1); + onCommandDestroyed: console.log("Command destroyed!"); + } + + Row { + anchors { + right: parent.right + top: parent.top + margins: 20 + } + spacing: 20 + + Button { + color: "red" + width: 100 + text: "Change color" + onClicked: stack.push(colorCommand, rec); + } + Button { + color: "blue" + text: "Undo" + onClicked: stack.undo(); + } + Button { + color: "green" + text: "Redo" + onClicked: stack.redo(); + } + } + + Rectangle { + id: rec + + x: 20 + y: 50 + width: 50 + height: 50 + color: "black" + + Drag.active: dragArea.drag.active + Drag.hotSpot.x: 10 + Drag.hotSpot.y: 10 + + MouseArea { + id: dragArea + + anchors.fill: parent + drag.target: parent + + onPressed: stack.push(moveCommand, parent); + } + } +} diff --git a/examples/undo/quickundo/quickundo.qmlproject b/examples/undo/quickundo/quickundo.qmlproject new file mode 100644 index 0000000..c1493d6 --- /dev/null +++ b/examples/undo/quickundo/quickundo.qmlproject @@ -0,0 +1,16 @@ +import QmlProject 1.0 + +Project { + /* Include .qml, .js, and image files from current directory and subdirectories */ + QmlFiles { + directory: "" + } + JavaScriptFiles { + directory: "" + } + ImageFiles { + directory: "" + } + /* List of plugin directories passed to QML runtime */ + //importPaths: [ "../../../src/imports/undo/" ] +} diff --git a/src/imports/imports.pro b/src/imports/imports.pro new file mode 100644 index 0000000..6abb48b --- /dev/null +++ b/src/imports/imports.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs + +SUBDIRS += undo diff --git a/src/imports/undo/plugin.cpp b/src/imports/undo/plugin.cpp new file mode 100644 index 0000000..0345e23 --- /dev/null +++ b/src/imports/undo/plugin.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the UiHelpers playground module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "uiquickundostack_p.h" +#include "uiquickundocommands_p.h" + + +class QmlUndoFrameworkPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + +public: + virtual void registerTypes(const char* uri); +}; + +void QmlUndoFrameworkPlugin::registerTypes(const char* uri) +{ + Q_ASSERT(QLatin1String(uri) == QLatin1String("Playground.UiHelpers.UndoFramework")); + + qmlRegisterType(uri, 1, 0, "UndoStack"); + qmlRegisterUncreatableType(uri, 1, 0, "", ""); + qmlRegisterType(uri, 1, 0, "UndoCommand"); + qmlRegisterType(uri, 1, 0, "UndoPropertyCommand"); +} + +#include "plugin.moc" + +Q_EXPORT_PLUGIN2(qmlundoframeworkplugin, QT_PREPEND_NAMESPACE(QmlUndoFrameworkPlugin)) diff --git a/src/imports/undo/qmldir b/src/imports/undo/qmldir new file mode 100644 index 0000000..e04cfa3 --- /dev/null +++ b/src/imports/undo/qmldir @@ -0,0 +1 @@ +plugin qmlundoframeworkplugin diff --git a/src/imports/undo/uiquickundocommands.cpp b/src/imports/undo/uiquickundocommands.cpp new file mode 100644 index 0000000..8130f9f --- /dev/null +++ b/src/imports/undo/uiquickundocommands.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the UiHelpers playground module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "uiquickundocommands_p.h" + + +UiQuickBaseUndoCommand::UiQuickBaseUndoCommand(QObject *parent) + : QObject(parent) +{ +} + +UiQuickBaseUndoCommand::~UiQuickBaseUndoCommand() +{ +} + +UiQuickUndoCommand::UiQuickUndoCommand(QObject *parent) + : UiQuickBaseUndoCommand(parent) +{ +} + +UiQuickUndoCommand::~UiQuickUndoCommand() +{ +} + +UndoCommand::UndoCommand(QObject* target, UiQuickUndoCommand *qmlObject) + : UiUndoCommand() + , m_target(target) + , m_qmlObject(qmlObject) +{ +} + +UndoCommand::~UndoCommand() +{ + emit m_qmlObject->commandDestroyed(m_target); +} + +void UndoCommand::undo() +{ + emit m_qmlObject->undo(m_target); +} + +void UndoCommand::redo() +{ + emit m_qmlObject->redo(m_target); +} + +// --------------------------------- // + +UiQuickUndoPropertyCommand::UiQuickUndoPropertyCommand(QObject *parent) + : UiQuickBaseUndoCommand(parent) + , m_properties(QVariantList()) +{ +} + +UiQuickUndoPropertyCommand::~UiQuickUndoPropertyCommand() +{ +} + +QVariantList UiQuickUndoPropertyCommand::properties() const +{ + return m_properties; +} + +void UiQuickUndoPropertyCommand::setProperties(const QVariantList& prop) +{ + m_properties = prop; + emit propertiesChanged(); +} + +UndoPropertyCommand::UndoPropertyCommand(QObject* t, UiQuickUndoPropertyCommand *q) + : UiUndoCommand() + , m_undoState(TargetState()) + , m_redoState(TargetState()) + , m_target(t) + , m_qmlObject(q) +{ + saveState(m_undoState); +} + +UndoPropertyCommand::~UndoPropertyCommand() +{ +} + +void UndoPropertyCommand::saveState(TargetState& state) +{ + foreach (const QVariant& var, m_qmlObject->properties()) { + QByteArray propertyName = var.toByteArray(); + state.append(qMakePair(propertyName, m_target->property(propertyName.data()))); + } +} + +void UndoPropertyCommand::applyState(TargetState& state) +{ + foreach (PropertyState pair, state) + m_target->setProperty(pair.first, pair.second); +} + +void UndoPropertyCommand::undo() +{ + applyState(m_undoState); +} + +void UndoPropertyCommand::redo() +{ + if (m_redoState.empty()) + saveState(m_redoState); + else + applyState(m_redoState); +} diff --git a/src/imports/undo/uiquickundocommands_p.h b/src/imports/undo/uiquickundocommands_p.h new file mode 100644 index 0000000..f5d46c2 --- /dev/null +++ b/src/imports/undo/uiquickundocommands_p.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the UiHelpers playground module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef UIQUICKUNDOCOMMAND_H +#define UIQUICKUNDOCOMMAND_H + +#include +#include + +QT_USE_NAMESPACE_UIHELPERS; + +class UiQuickBaseUndoCommand : public QObject +{ + Q_OBJECT + +public: + UiQuickBaseUndoCommand(QObject *parent = 0); + ~UiQuickBaseUndoCommand(); +}; + +// ------- // + +class UiQuickUndoCommand : public UiQuickBaseUndoCommand +{ + Q_OBJECT + +public: + UiQuickUndoCommand(QObject *parent = 0); + ~UiQuickUndoCommand(); + +signals: + void undo(QObject *target); + void redo(QObject *target); + void commandDestroyed(QObject *target); +}; + +class UndoCommand : public UiUndoCommand +{ +public: + UndoCommand(QObject* target, UiQuickUndoCommand *m_qmlObject); + ~UndoCommand(); + + void undo(); + void redo(); + +private: + QObject *m_target; + UiQuickUndoCommand *m_qmlObject; +}; + +// -----------------// + +class UiQuickUndoPropertyCommand : public UiQuickBaseUndoCommand +{ + Q_OBJECT + + Q_PROPERTY(QVariantList properties READ properties WRITE setProperties NOTIFY propertiesChanged) + +public: + UiQuickUndoPropertyCommand(QObject *parent = 0); + ~UiQuickUndoPropertyCommand(); + + QVariantList properties() const; + void setProperties(const QVariantList& prop); + +signals: + void propertiesChanged(); + +private: + QVariantList m_properties; +}; + +typedef QPair PropertyState; +typedef QList TargetState; + +class UndoPropertyCommand : public UiUndoCommand +{ + +public: + UndoPropertyCommand(QObject*, UiQuickUndoPropertyCommand*); + ~UndoPropertyCommand(); + + void undo(); + void redo(); + +private: + void saveState(TargetState& state); + void applyState(TargetState& state); + + TargetState m_undoState; + TargetState m_redoState; + QObject *m_target; + UiQuickUndoPropertyCommand *m_qmlObject; +}; + +#endif diff --git a/src/imports/undo/uiquickundostack.cpp b/src/imports/undo/uiquickundostack.cpp new file mode 100644 index 0000000..97adf9f --- /dev/null +++ b/src/imports/undo/uiquickundostack.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the UiHelpers playground module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "uiquickundostack_p.h" +#include "uiquickundocommands_p.h" + +UiQuickUndoStack::UiQuickUndoStack(QObject *parent) + : QObject(parent) + , m_stack(new UndoStack(this)) +{ +} + +UiQuickUndoStack::~UiQuickUndoStack() +{ +} + +UndoStack::UndoStack(QObject *parent) + : UiUndoStack(parent) + , currentCommand(0) +{ +} + +UndoStack::~UndoStack() +{ +} + +void UiQuickUndoStack::push(UiQuickBaseUndoCommand *cmd, QObject *target) +{ + if (!cmd || !target) + return; // XXX: notify error + + m_stack->commit(); + + UiQuickUndoPropertyCommand *upc = qobject_cast(cmd); + if (upc) { + m_stack->currentCommand = new UndoPropertyCommand(target, upc); + } else { + UiQuickUndoCommand *uc = qobject_cast(cmd); + m_stack->push(new UndoCommand(target, uc)); + } +} + +void UiQuickUndoStack::undo() +{ + m_stack->commit(); + m_stack->undo(); +} + +void UiQuickUndoStack::redo() +{ + m_stack->commit(); + m_stack->redo(); +} + +void UndoStack::commit() +{ + if (!currentCommand) + return; + + push(currentCommand); + currentCommand = 0; +} diff --git a/src/imports/undo/uiquickundostack_p.h b/src/imports/undo/uiquickundostack_p.h new file mode 100644 index 0000000..f7b35d5 --- /dev/null +++ b/src/imports/undo/uiquickundostack_p.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the UiHelpers playground module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef UIQUICKUNDOSTACK_H +#define UIQUICKUNDOSTACK_H + +#include +#include + + +QT_USE_NAMESPACE_UIHELPERS; + +class UndoStack; +class UiQuickBaseUndoCommand; + +class UiQuickUndoStack : public QObject +{ + Q_OBJECT + +public: + UiQuickUndoStack(QObject *parent = 0); + ~UiQuickUndoStack(); + +public slots: + void push(UiQuickBaseUndoCommand *cmd, QObject *target); + void undo(); + void redo(); + +private: + UndoStack *m_stack; +}; + +class UndoStack : public UiUndoStack +{ + Q_OBJECT + +public: + UndoStack(QObject *parent = 0); + ~UndoStack(); + + void commit(); + + UiUndoCommand *currentCommand; +}; + +#endif diff --git a/src/imports/undo/undo.pro b/src/imports/undo/undo.pro new file mode 100644 index 0000000..b9289e7 --- /dev/null +++ b/src/imports/undo/undo.pro @@ -0,0 +1,24 @@ +TEMPLATE = lib +TARGET = qmlundoframeworkplugin +TARGETPATH = Playground/UiHelpers/UndoFramework + +QT += qml uihelpers + +CONFIG += qt plugin + +SOURCES += plugin.cpp + +SOURCES += uiquickundocommands.cpp \ + uiquickundostack.cpp + +HEADERS += uiquickundocommands_p.h \ + uiquickundostack_p.h + + +DESTDIR = $$QT.qml.imports/$$TARGETPATH +target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH + +qmldir.files += $$PWD/qmldir +qmldir.path += $$[QT_INSTALL_IMPORTS]/$$TARGETPATH + +INSTALLS += target qmldir diff --git a/uihelpers.pro b/uihelpers.pro index e71cc1e..c1e84ca 100644 --- a/uihelpers.pro +++ b/uihelpers.pro @@ -4,6 +4,9 @@ CONFIG += ordered module_uihelpers_src.subdir = src module_uihelpers_src.target = module-uihelpers-src +module_uihelpers_plugin.subdir = src/imports +module_uihelpers_plugin.target = module-uihelpers-plugin + module_uihelpers_examples.subdir = examples module_uihelpers_examples.target = module-uihelpers-examples @@ -13,5 +16,6 @@ module_uihelpers_tests.depends = module_uihelpers_src module_uihelpers_tests.CONFIG = no_default_install SUBDIRS += module_uihelpers_src \ + module_uihelpers_plugin \ module_uihelpers_examples \ module_uihelpers_tests -- cgit v1.2.3