Cutecash: Add QUndoStack to implement all editing through the Command pattern and make it undoable.

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@18887 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Christian Stimming 2010-03-10 17:51:12 +00:00
parent 4bb186ef14
commit 0f09fc5e32
4 changed files with 144 additions and 29 deletions

100
src/gnc/Cmd.hpp Normal file
View File

@ -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@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

View File

@ -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 @@ extern "C"
#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 @@ static QofLogModule log_module = GNC_MOD_GUI;
MainWindow::MainWindow()
: ui(new Ui::MainWindow)
, m_undoStack(new QUndoStack(this))
{
ui->setupUi(this);
@ -79,6 +86,8 @@ MainWindow::MainWindow()
// 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,7 +159,16 @@ void MainWindow::on_actionAbout_triggered()
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()
@ -167,6 +185,21 @@ void MainWindow::createActions()
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 @@ void MainWindow::setCurrentFile(const QString &fileName)
// 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)

View File

@ -32,6 +32,7 @@ class QMenu;
class QPlainTextEdit;
class QTextEdit;
class QTabWidget;
class QUndoStack;
namespace Ui
{
@ -54,6 +55,7 @@ public:
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 @@ private:
QString strippedName(const QString &fullFileName);
void viewOrHideTab(bool checkedView, QWidget *widget);
void reallyRemoveTab(int index);
void updateWindowTitle();
Ui::MainWindow *ui;
@ -94,6 +97,7 @@ private:
QToolBar *fileToolBar;
QToolBar *editToolBar;
RecentFileMenu *menuRecentFiles;
QUndoStack *m_undoStack;
Session m_session;
AccountListModel *m_accountListModel;

View File

@ -174,9 +174,6 @@ p, li { white-space: pre-wrap; }
<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 @@ p, li { white-space: pre-wrap; }
<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>