diff --git a/src/gnc/CMakeLists.txt b/src/gnc/CMakeLists.txt index e720b4132a..a903f47419 100644 --- a/src/gnc/CMakeLists.txt +++ b/src/gnc/CMakeLists.txt @@ -12,6 +12,7 @@ LINK_DIRECTORIES (${GLIB2_LIBRARY_DIRS} SET (gnc_SOURCES AccountItemModel.cpp Book.cpp + Cmd.cpp Numeric.cpp RecentFileMenu.cpp Session.cpp @@ -30,6 +31,7 @@ SET (gnc_QOBJECT_HEADERS SET (gnc_HEADERS ${gnc_QOBJECT_HEADERS} Account.hpp Book.hpp + Cmd.hpp Session.hpp Split.hpp Transaction.hpp diff --git a/src/gnc/Cmd.cpp b/src/gnc/Cmd.cpp new file mode 100644 index 0000000000..9498966dbd --- /dev/null +++ b/src/gnc/Cmd.cpp @@ -0,0 +1,91 @@ +/* + * 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 + */ + +#include "Cmd.hpp" +#include "gnc/Split.hpp" +#include "gnc/Account.hpp" +#include "gnc/Transaction.hpp" +#include + +namespace gnc +{ + +// Explicit instantiations to check for compiler errors +template class Cmd; + +namespace cmd +{ + +QUndoCommand* setSplitMemo(Split& t, const QString& newValue) +{ + return new Cmd(QObject::tr("Edit Split Memo"), + t, &Split::setMemo, + &Split::getMemo, newValue); +} + +QUndoCommand* setSplitAction(Split& t, const QString& newValue) +{ + return new Cmd(QObject::tr("Edit Split Action"), + t, &Split::setAction, + &Split::getAction, newValue); +} + +QUndoCommand* setSplitReconcile(Split& t, char newValue) +{ + return new Cmd(QObject::tr("Edit Split Reconcile"), + t, &Split::setReconcile, + &Split::getReconcile, newValue); +} + +QUndoCommand* setTransactionNum(Transaction& t, const QString& newValue) +{ + return new Cmd(QObject::tr("Edit Transaction Number"), + t, &Transaction::setNum, + &Transaction::getNum, newValue); +} + +QUndoCommand* setTransactionDescription(Transaction& t, const QString& newValue) +{ + return new Cmd(QObject::tr("Edit Transaction Description"), + t, &Transaction::setDescription, + &Transaction::getDescription, newValue); +} + +QUndoCommand* setTransactionNotes(Transaction& t, const QString& newValue) +{ + return new Cmd(QObject::tr("Edit Transaction Notes"), + t, &Transaction::setNotes, + &Transaction::getNotes, newValue); +} + +QUndoCommand* setTransactionDate(Transaction& t, const QDateTime& newValue) +{ + return new Cmd(QObject::tr("Edit Transaction Date"), + t, &Transaction::setDatePosted, + &Transaction::getDatePosted, newValue); +} + + +} // END namespace cmd + + +} // END namespace gnc diff --git a/src/gnc/Cmd.hpp b/src/gnc/Cmd.hpp index 74b7c99603..a979b1c308 100644 --- a/src/gnc/Cmd.hpp +++ b/src/gnc/Cmd.hpp @@ -24,11 +24,16 @@ #define GNC_CMD_HPP #include -#include +#include +#include namespace gnc { +class Split; +class Account; +class Transaction; + template class Cmd : public QUndoCommand { @@ -38,26 +43,27 @@ public: 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, +// 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, + WeakPointer& targetPtr, + setter_func setter, getter_func getter, const value_type& newValue, QUndoCommand *parent = 0) : QUndoCommand(text, parent) - , m_target(target) + , m_target(targetPtr.get()) , m_setter(setter) , m_previousValue((m_target.*getter)()) , m_newValue(newValue) @@ -77,7 +83,7 @@ public: protected: - TargetT& m_target; + TargetT m_target; setter_func m_setter; value_type m_previousValue; value_type m_newValue; @@ -86,12 +92,18 @@ protected: namespace cmd { -QUndoCommand* setSplitMemo(Split& split, const QString& newValue) -{ - return new Cmd(QWidget::tr("Edit Split Memo"), - split, &Split::setMemo, - &Split::getMemo, newValue); -} +// This is the collection of command objects which are already +// provided for the different data types and their simple +// members. Just create one of those, add it to a QUndoStack, and +// magically the values will change with undo/redo back and +// forth. Spooky, IMHO. +QUndoCommand* setSplitMemo(Split& split, const QString& newValue); +QUndoCommand* setSplitAction(Split& t, const QString& newValue); +QUndoCommand* setSplitReconcile(Split& t, char newValue); +QUndoCommand* setTransactionNum(Transaction& t, const QString& newValue); +QUndoCommand* setTransactionDescription(Transaction& t, const QString& newValue); +QUndoCommand* setTransactionNotes(Transaction& t, const QString& newValue); +QUndoCommand* setTransactionDate(Transaction& t, const QDateTime& newValue); } // END namespace cmd diff --git a/src/gnc/RecentFileMenu.cpp b/src/gnc/RecentFileMenu.cpp index 4628cf79b8..8e8c873145 100644 --- a/src/gnc/RecentFileMenu.cpp +++ b/src/gnc/RecentFileMenu.cpp @@ -80,7 +80,7 @@ void RecentFileMenu::updateMenu() const QString& qs = m_fileNames.at(i); QAction *act = m_actionRecentFile[i]; act->setVisible(true); - act->setText(tr("&%1 %2").arg(i+1).arg(QFileInfo(qs).fileName())); + act->setText(tr("&%1 %2").arg(i + 1).arg(QFileInfo(qs).fileName())); act->setStatusTip(qs); act->setData(qs); } diff --git a/src/gnc/Split.hpp b/src/gnc/Split.hpp index c198294bcc..acf318c30f 100644 --- a/src/gnc/Split.hpp +++ b/src/gnc/Split.hpp @@ -68,7 +68,7 @@ public: void setAction(const QString& v) { xaccSplitSetAction(get(), v.toUtf8()); } char getReconcile() const { return xaccSplitGetReconcile(get()); } - void setReconcile(char v) { xaccSplitSetReconcile(get(), v); } + void setReconcile(const char& v) { xaccSplitSetReconcile(get(), v); } Split getOtherSplit() const { return xaccSplitGetOtherSplit(get()); } diff --git a/src/gnc/SplitListModel.cpp b/src/gnc/SplitListModel.cpp index 632b59532a..30ea6f3a31 100644 --- a/src/gnc/SplitListModel.cpp +++ b/src/gnc/SplitListModel.cpp @@ -22,14 +22,17 @@ #include "SplitListModel.hpp" #include "gnc/Transaction.hpp" +#include "gnc/Cmd.hpp" #include +#include namespace gnc { -SplitListModel::SplitListModel(const SplitQList splits, QObject *parent) +SplitListModel::SplitListModel(const SplitQList splits, QUndoStack* undoStack, QObject *parent) : QAbstractItemModel(parent) , m_list(splits) + , m_undoStack(undoStack) { } @@ -100,8 +103,16 @@ Qt::ItemFlags SplitListModel::flags(const QModelIndex &index) const if (!index.isValid()) return 0; - // Ensure read-only access only - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + Qt::ItemFlags result = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + switch (index.column()) + { + case 2: + // Allow write access as well + return result | Qt::ItemIsEditable; + default: + // Ensure read-only access only + return result; + } } QVariant SplitListModel::headerData(int section, Qt::Orientation orientation, int role) const @@ -133,5 +144,28 @@ QVariant SplitListModel::headerData(int section, Qt::Orientation orientation, in return QString("%1").arg(1 + section); } +bool SplitListModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (index.isValid() && role == Qt::EditRole) + { + Split split(static_cast< ::Split*>(index.internalPointer())); + Transaction trans(split.getParent()); + switch (index.column()) + { + case 2: + // We allow to edit column 2. "Editing" is done by + // creating a Cmd-object and adding it to the undo + // stack. That's in fact all that was needed to create an + // *undoable* edit of this data cell. Seems almost spooky, + // doesn't it? + m_undoStack->push(cmd::setTransactionDescription(trans, value.toString())); + emit dataChanged(index, index); + return true; + default: + return false; + } + } + return false; +} } // END namespace gnc diff --git a/src/gnc/SplitListModel.hpp b/src/gnc/SplitListModel.hpp index 5637855e0c..5a478921bb 100644 --- a/src/gnc/SplitListModel.hpp +++ b/src/gnc/SplitListModel.hpp @@ -26,6 +26,7 @@ #include "gnc/Split.hpp" #include +class QUndoStack; namespace gnc { @@ -36,7 +37,7 @@ class SplitListModel : public QAbstractItemModel { Q_OBJECT public: - SplitListModel(const SplitQList splits, QObject *parent = 0); + SplitListModel(const SplitQList splits, QUndoStack* undoStack, QObject *parent = 0); QModelIndex parent(const QModelIndex &index) const { return QModelIndex(); } int rowCount(const QModelIndex& parent = QModelIndex()) const { return m_list.size(); } @@ -47,9 +48,12 @@ public: QVariant data(const QModelIndex& index, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; + bool setData(const QModelIndex &index, const QVariant &value, int role); + protected: SplitQList m_list; + QUndoStack* m_undoStack; }; } // END namespace gnc diff --git a/src/gnc/Transaction.hpp b/src/gnc/Transaction.hpp index ef8f1f4998..735ce38513 100644 --- a/src/gnc/Transaction.hpp +++ b/src/gnc/Transaction.hpp @@ -61,8 +61,8 @@ public: int countSplits() const { return xaccTransCountSplits(get()); } - void setDatePosted(const QDateTime& t); - void setDateEntered(const QDateTime& t); + void setDatePosted(const QDateTime& t) { xaccTransSetDatePostedSecs(get(), t.toTime_t()); } + void setDateEntered(const QDateTime& t) { xaccTransSetDateEnteredSecs(get(), t.toTime_t()); } QDateTime getDatePosted() const { return toQDateTime(xaccTransRetDatePostedTS(get())); } QDateTime getDateEntered() const { return toQDateTime(xaccTransRetDateEnteredTS(get())); } diff --git a/src/gnc/mainwindow.cpp b/src/gnc/mainwindow.cpp index bafdde2340..853da3fcbd 100644 --- a/src/gnc/mainwindow.cpp +++ b/src/gnc/mainwindow.cpp @@ -57,9 +57,6 @@ extern "C" namespace gnc { -// Explicit instantiations to check for compiler errors -template class Cmd; - inline QString errorToString(QofBackendError err) { return errorToStringPair(err).first; @@ -420,7 +417,7 @@ void MainWindow::accountItemActivated(const QModelIndex & index) // We create a new model for this list of splits and also a view // widget for this list. QTableView *tableView = new QTableView(ui->tabWidget); // FIXME: Is this parent correct? - SplitListModel *smodel = new SplitListModel(Split::fromGList(slist), tableView); + SplitListModel *smodel = new SplitListModel(Split::fromGList(slist), m_undoStack, tableView); tableView->setModel(smodel); tableView->setAlternatingRowColors(true);