r18887 - gnucash/trunk/src/gnc - Cutecash: Add QUndoStack to implement all editing through the Command pattern and make it undoable.

Christian Stimming cstim at code.gnucash.org
Wed Mar 10 12:51:12 EST 2010


Author: cstim
Date: 2010-03-10 12:51:12 -0500 (Wed, 10 Mar 2010)
New Revision: 18887
Trac: http://svn.gnucash.org/trac/changeset/18887

Added:
   gnucash/trunk/src/gnc/Cmd.hpp
Modified:
   gnucash/trunk/src/gnc/mainwindow.cpp
   gnucash/trunk/src/gnc/mainwindow.hpp
   gnucash/trunk/src/gnc/mainwindow.ui
Log:
Cutecash: Add QUndoStack to implement all editing through the Command pattern and make it undoable.

Added: gnucash/trunk/src/gnc/Cmd.hpp
===================================================================
--- gnucash/trunk/src/gnc/Cmd.hpp	                        (rev 0)
+++ gnucash/trunk/src/gnc/Cmd.hpp	2010-03-10 17:51:12 UTC (rev 18887)
@@ -0,0 +1,100 @@
+/*
+ * Cmd.hpp
+ * Copyright (C) 2010 Christian Stimming
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact:
+ *
+ * Free Software Foundation           Voice:  +1-617-542-5942
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org
+ */
+
+#ifndef GNC_CMD_HPP
+#define GNC_CMD_HPP
+
+#include <QUndoCommand>
+#include <gnc/Split.hpp>
+
+namespace gnc
+{
+
+template<class TargetT, class ValueT>
+class Cmd : public QUndoCommand
+{
+public:
+    typedef TargetT target_type;
+    typedef ValueT value_type;
+    typedef void (TargetT::*setter_func)(const value_type&);
+    typedef value_type (TargetT::*getter_func)() const;
+
+    Cmd(const QString& text,
+        TargetT& target, setter_func setter,
+        const value_type& previousValue,
+        const value_type& newValue,
+        QUndoCommand *parent = 0)
+            : QUndoCommand(text, parent)
+            , m_target(target)
+            , m_setter(setter)
+            , m_previousValue(previousValue)
+            , m_newValue(newValue)
+    {
+    }
+
+    Cmd(const QString& text,
+        TargetT& target, setter_func setter,
+        getter_func getter,
+        const value_type& newValue,
+        QUndoCommand *parent = 0)
+            : QUndoCommand(text, parent)
+            , m_target(target)
+            , m_setter(setter)
+            , m_previousValue((m_target.*getter)())
+            , m_newValue(newValue)
+    {
+    }
+
+    virtual void redo()
+    {
+        // Uh oh.  The calling syntax for pointer-to-member variables
+        // (here: m_setter) looks rather weird:
+        (m_target.*m_setter)(m_newValue);
+    }
+    virtual void undo()
+    {
+        (m_target.*m_setter)(m_previousValue);
+    }
+
+
+protected:
+    TargetT& m_target;
+    setter_func m_setter;
+    value_type m_previousValue;
+    value_type m_newValue;
+};
+
+namespace cmd
+{
+
+QUndoCommand* setSplitMemo(Split& split, const QString& newValue)
+{
+    return new Cmd<Split, QString>(QWidget::tr("Edit Split Memo"),
+                                   split, &Split::setMemo,
+                                   &Split::getMemo, newValue);
+}
+
+} // END namespace cmd
+
+} // END namespace gnc
+
+#endif

Modified: gnucash/trunk/src/gnc/mainwindow.cpp
===================================================================
--- gnucash/trunk/src/gnc/mainwindow.cpp	2010-03-10 17:50:51 UTC (rev 18886)
+++ gnucash/trunk/src/gnc/mainwindow.cpp	2010-03-10 17:51:12 UTC (rev 18887)
@@ -26,6 +26,7 @@
 #include <QtGui/QMessageBox>
 #include <QtGui/QToolBar>
 #include <QtGui/QProgressBar>
+#include <QtGui/QUndoStack>
 #include <QDebug>
 
 #include "config.h"
@@ -51,9 +52,14 @@
 #include "gnc/SplitListModel.hpp"
 #include "gnc/RecentFileMenu.hpp"
 
+#include "gnc/Cmd.hpp"
+
 namespace gnc
 {
 
+// Explicit instantiations to check for compiler errors
+template class Cmd<Account, QString>;
+
 inline QString errorToString(QofBackendError err)
 {
     return errorToStringPair(err).first;
@@ -68,6 +74,7 @@
 
 MainWindow::MainWindow()
         : ui(new Ui::MainWindow)
+        , m_undoStack(new QUndoStack(this))
 {
     ui->setupUi(this);
 
@@ -79,6 +86,8 @@
 
 //     connect(ui->labelMain, SIGNAL(linkActivated(const QString&)),
 //             this, SLOT(documentWasModified()));
+    connect(m_undoStack, SIGNAL(cleanChanged(bool)),
+            this, SLOT(documentCleanStateChanged(bool)));
 
     setWindowIcon(QIcon(":/pixmaps/gnucash-icon-32x32.png"));
 
@@ -150,9 +159,18 @@
 
 void MainWindow::documentWasModified()
 {
-//     setWindowModified(ui->textEdit->document()->isModified());
+    setWindowModified(true);
 }
 
+void MainWindow::documentCleanStateChanged(bool clean)
+{
+    bool unchanged = (clean == isWindowModified());
+
+    setWindowModified(!clean);
+    if (!unchanged)
+        updateWindowTitle();
+}
+
 // Auto-connected to ui->textBrowser's signal anchorClicked()
 void MainWindow::on_textBrowser_anchorClicked(const QUrl &url)
 {
@@ -167,6 +185,21 @@
     ui->actionOpen->setShortcuts(QKeySequence::Open);
     ui->actionSave->setShortcuts(QKeySequence::Save);
     ui->actionSave_as->setShortcuts(QKeySequence::SaveAs);
+
+    QAction *redo = m_undoStack->createRedoAction(ui->menuEdit, tr("&Redo"));
+    redo->setIcon(QIcon(":/gtk-icons/gtk-redo.png"));
+    redo->setShortcuts(QKeySequence::Redo);
+    QAction *undo = m_undoStack->createUndoAction(ui->menuEdit, tr("&Undo"));
+    undo->setIcon(QIcon(":/gtk-icons/gtk-undo.png"));
+    undo->setShortcuts(QKeySequence::Undo);
+    ui->menuEdit->insertAction(ui->actionCut, undo);
+    ui->menuEdit->insertAction(ui->actionCut, redo);
+    ui->menuEdit->insertSeparator(ui->actionCut);
+
+    ui->actionCut->setShortcuts(QKeySequence::Cut);
+    ui->actionCopy->setShortcuts(QKeySequence::Copy);
+    ui->actionPaste->setShortcuts(QKeySequence::Paste);
+
     ui->actionViewClose->setShortcuts(QKeySequence::Close);
 
     connect(ui->actionNew, SIGNAL(triggered()), this, SLOT(newFile()));
@@ -257,13 +290,18 @@
 //     ui->textEdit->document()->setModified(false);
     setWindowModified(false);
 
+    updateWindowTitle();
+}
+
+void MainWindow::updateWindowTitle()
+{
     QString shownName;
     if (curFile.isEmpty())
         shownName = "untitled.txt";
     else
         shownName = strippedName(curFile);
 
-    setWindowTitle(tr("%1[*] - %2").arg(shownName).arg(tr("Application")));
+    setWindowTitle(tr("%1[*]%2 - %3").arg(shownName).arg(isWindowModified() ? "(*)" : "").arg(tr("Application")));
 }
 
 QString MainWindow::strippedName(const QString &fullFileName)

Modified: gnucash/trunk/src/gnc/mainwindow.hpp
===================================================================
--- gnucash/trunk/src/gnc/mainwindow.hpp	2010-03-10 17:50:51 UTC (rev 18886)
+++ gnucash/trunk/src/gnc/mainwindow.hpp	2010-03-10 17:51:12 UTC (rev 18887)
@@ -32,6 +32,7 @@
 class QPlainTextEdit;
 class QTextEdit;
 class QTabWidget;
+class QUndoStack;
 
 namespace Ui
 {
@@ -54,6 +55,7 @@
 public slots:
     void accountItemActivated(const QModelIndex & index);
     void loadFileMaybe(const QString &fileName);
+    void documentCleanStateChanged(bool clean);
 
 protected:
     void closeEvent(QCloseEvent *event);
@@ -86,6 +88,7 @@
     QString strippedName(const QString &fullFileName);
     void viewOrHideTab(bool checkedView, QWidget *widget);
     void reallyRemoveTab(int index);
+    void updateWindowTitle();
 
     Ui::MainWindow *ui;
 
@@ -94,6 +97,7 @@
     QToolBar *fileToolBar;
     QToolBar *editToolBar;
     RecentFileMenu *menuRecentFiles;
+    QUndoStack *m_undoStack;
 
     Session m_session;
     AccountListModel *m_accountListModel;

Modified: gnucash/trunk/src/gnc/mainwindow.ui
===================================================================
--- gnucash/trunk/src/gnc/mainwindow.ui	2010-03-10 17:50:51 UTC (rev 18886)
+++ gnucash/trunk/src/gnc/mainwindow.ui	2010-03-10 17:51:12 UTC (rev 18887)
@@ -174,9 +174,6 @@
     <property name="title">
      <string>&amp;Edit</string>
     </property>
-    <addaction name="action_Undo"/>
-    <addaction name="action_Redo"/>
-    <addaction name="separator"/>
     <addaction name="actionCut"/>
     <addaction name="actionCopy"/>
     <addaction name="actionPaste"/>
@@ -368,30 +365,6 @@
     <string>About Qt</string>
    </property>
   </action>
-  <action name="action_Undo">
-   <property name="enabled">
-    <bool>false</bool>
-   </property>
-   <property name="icon">
-    <iconset resource="gtk-icons.qrc">
-     <normaloff>:/gtk-icons/gtk-undo.png</normaloff>:/gtk-icons/gtk-undo.png</iconset>
-   </property>
-   <property name="text">
-    <string>&amp;Undo</string>
-   </property>
-  </action>
-  <action name="action_Redo">
-   <property name="enabled">
-    <bool>false</bool>
-   </property>
-   <property name="icon">
-    <iconset resource="gtk-icons.qrc">
-     <normaloff>:/gtk-icons/gtk-redo.png</normaloff>:/gtk-icons/gtk-redo.png</iconset>
-   </property>
-   <property name="text">
-    <string>&amp;Redo</string>
-   </property>
-  </action>
   <action name="actionViewWelcomepage">
    <property name="checkable">
     <bool>true</bool>



More information about the gnucash-changes mailing list