mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Enable editing of the "Description" column in the split list view - WITH UNDO!
The Qt Undo framework is almost like magic. We just have to create a command object instead of directly manipulating the value, and suddenly the undo/redo just works. This is fun! git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@18889 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
0a2d901f71
commit
81ec044f82
@ -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
|
||||
|
91
src/gnc/Cmd.cpp
Normal file
91
src/gnc/Cmd.cpp
Normal file
@ -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 <QObject>
|
||||
|
||||
namespace gnc
|
||||
{
|
||||
|
||||
// Explicit instantiations to check for compiler errors
|
||||
template class Cmd<Account, QString>;
|
||||
|
||||
namespace cmd
|
||||
{
|
||||
|
||||
QUndoCommand* setSplitMemo(Split& t, const QString& newValue)
|
||||
{
|
||||
return new Cmd<Split, QString>(QObject::tr("Edit Split Memo"),
|
||||
t, &Split::setMemo,
|
||||
&Split::getMemo, newValue);
|
||||
}
|
||||
|
||||
QUndoCommand* setSplitAction(Split& t, const QString& newValue)
|
||||
{
|
||||
return new Cmd<Split, QString>(QObject::tr("Edit Split Action"),
|
||||
t, &Split::setAction,
|
||||
&Split::getAction, newValue);
|
||||
}
|
||||
|
||||
QUndoCommand* setSplitReconcile(Split& t, char newValue)
|
||||
{
|
||||
return new Cmd<Split, char>(QObject::tr("Edit Split Reconcile"),
|
||||
t, &Split::setReconcile,
|
||||
&Split::getReconcile, newValue);
|
||||
}
|
||||
|
||||
QUndoCommand* setTransactionNum(Transaction& t, const QString& newValue)
|
||||
{
|
||||
return new Cmd<Transaction, QString>(QObject::tr("Edit Transaction Number"),
|
||||
t, &Transaction::setNum,
|
||||
&Transaction::getNum, newValue);
|
||||
}
|
||||
|
||||
QUndoCommand* setTransactionDescription(Transaction& t, const QString& newValue)
|
||||
{
|
||||
return new Cmd<Transaction, QString>(QObject::tr("Edit Transaction Description"),
|
||||
t, &Transaction::setDescription,
|
||||
&Transaction::getDescription, newValue);
|
||||
}
|
||||
|
||||
QUndoCommand* setTransactionNotes(Transaction& t, const QString& newValue)
|
||||
{
|
||||
return new Cmd<Transaction, QString>(QObject::tr("Edit Transaction Notes"),
|
||||
t, &Transaction::setNotes,
|
||||
&Transaction::getNotes, newValue);
|
||||
}
|
||||
|
||||
QUndoCommand* setTransactionDate(Transaction& t, const QDateTime& newValue)
|
||||
{
|
||||
return new Cmd<Transaction, QDateTime>(QObject::tr("Edit Transaction Date"),
|
||||
t, &Transaction::setDatePosted,
|
||||
&Transaction::getDatePosted, newValue);
|
||||
}
|
||||
|
||||
|
||||
} // END namespace cmd
|
||||
|
||||
|
||||
} // END namespace gnc
|
@ -24,11 +24,16 @@
|
||||
#define GNC_CMD_HPP
|
||||
|
||||
#include <QUndoCommand>
|
||||
#include <gnc/Split.hpp>
|
||||
#include <gnc/WeakPointer.hpp>
|
||||
#include <gnc/Numeric.hpp>
|
||||
|
||||
namespace gnc
|
||||
{
|
||||
|
||||
class Split;
|
||||
class Account;
|
||||
class Transaction;
|
||||
|
||||
template<class TargetT, class ValueT>
|
||||
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<typename TargetT::element_type>& 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<Split, QString>(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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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()); }
|
||||
|
||||
|
@ -22,14 +22,17 @@
|
||||
|
||||
#include "SplitListModel.hpp"
|
||||
#include "gnc/Transaction.hpp"
|
||||
#include "gnc/Cmd.hpp"
|
||||
#include <QDebug>
|
||||
#include <QUndoStack>
|
||||
|
||||
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;
|
||||
|
||||
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 Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
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
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "gnc/Split.hpp"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
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
|
||||
|
@ -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())); }
|
||||
|
||||
|
@ -57,9 +57,6 @@ extern "C"
|
||||
namespace gnc
|
||||
{
|
||||
|
||||
// Explicit instantiations to check for compiler errors
|
||||
template class Cmd<Account, QString>;
|
||||
|
||||
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user