r18927 - gnucash/trunk/src/gnc - Cutecash: Add deletion of rows/transactions (through "Cut"). With Undo. Hee Hee.
Christian Stimming
cstim at code.gnucash.org
Wed Mar 17 17:28:51 EDT 2010
Author: cstim
Date: 2010-03-17 17:28:51 -0400 (Wed, 17 Mar 2010)
New Revision: 18927
Trac: http://svn.gnucash.org/trac/changeset/18927
Modified:
gnucash/trunk/src/gnc/Cmd.cpp
gnucash/trunk/src/gnc/Cmd.hpp
gnucash/trunk/src/gnc/QofEventWrapper.hpp
gnucash/trunk/src/gnc/Split.cpp
gnucash/trunk/src/gnc/Split.hpp
gnucash/trunk/src/gnc/SplitListModel.cpp
gnucash/trunk/src/gnc/SplitListModel.hpp
gnucash/trunk/src/gnc/Transaction.hpp
gnucash/trunk/src/gnc/mainwindow.cpp
gnucash/trunk/src/gnc/mainwindow.hpp
Log:
Cutecash: Add deletion of rows/transactions (through "Cut"). With Undo. Hee Hee.
Modified: gnucash/trunk/src/gnc/Cmd.cpp
===================================================================
--- gnucash/trunk/src/gnc/Cmd.cpp 2010-03-17 19:24:01 UTC (rev 18926)
+++ gnucash/trunk/src/gnc/Cmd.cpp 2010-03-17 21:28:51 UTC (rev 18927)
@@ -178,7 +178,54 @@
t.getDatePosted(), newValue);
}
+// ////////////////////////////////////////////////////////////
+class TransactionDestroyCmd : public QUndoCommand
+{
+public:
+ typedef QUndoCommand base_class;
+ typedef Transaction target_type;
+
+ /** Constructor
+ */
+ TransactionDestroyCmd(const QString& text,
+ WeakPointer<target_type::element_type>& targetPtr,
+ QUndoCommand *parent = 0)
+ : base_class(text, parent)
+ , m_target(targetPtr.get())
+ , m_previousValue(m_target)
+ , m_book(m_target.getBook())
+ {
+ Q_ASSERT(m_target);
+ }
+
+ virtual void redo()
+ {
+ xaccTransDestroy(m_target.get());
+ m_target.reset();
+ }
+
+ virtual void undo()
+ {
+ m_target.reset(xaccMallocTransaction (m_book.get()));
+ m_target.beginEdit();
+ m_previousValue.copyTo(m_target);
+ m_target.commitEdit();
+ }
+
+protected:
+ target_type m_target;
+ TmpTransaction m_previousValue;
+ Book m_book;
+};
+
+QUndoCommand* destroyTransaction(Transaction& t)
+{
+ return new TransactionDestroyCmd(QObject::tr("Delete Transaction"),
+ t);
+}
+
+
} // END namespace cmd
Modified: gnucash/trunk/src/gnc/Cmd.hpp
===================================================================
--- gnucash/trunk/src/gnc/Cmd.hpp 2010-03-17 19:24:01 UTC (rev 18926)
+++ gnucash/trunk/src/gnc/Cmd.hpp 2010-03-17 21:28:51 UTC (rev 18927)
@@ -166,6 +166,7 @@
QUndoCommand* setTransactionNotes(Transaction& t, const QString& newValue);
QUndoCommand* setTransactionDate(Transaction& t, const QDate& newValue);
QUndoCommand* setSplitValueAndAmount(Split& t, const Numeric& newValue);
+QUndoCommand* destroyTransaction(Transaction& t);
} // END namespace cmd
Modified: gnucash/trunk/src/gnc/QofEventWrapper.hpp
===================================================================
--- gnucash/trunk/src/gnc/QofEventWrapper.hpp 2010-03-17 19:24:01 UTC (rev 18926)
+++ gnucash/trunk/src/gnc/QofEventWrapper.hpp 2010-03-17 21:28:51 UTC (rev 18927)
@@ -52,18 +52,16 @@
* The receiver's class is the first template argument; the argument
* type of the to-be-called member function is the second template
* (usually a pointer type). */
-template<class ReceiverT, class ValuePtrT, typename SlotFunc = void (ReceiverT::*)(ValuePtrT)>
+template<class ReceiverT, class ValuePtrT, typename SlotFunc = void (ReceiverT::*)(ValuePtrT, QofEventId)>
class QofEventWrapper
{
public:
QofEventWrapper(ReceiverT& receiver,
SlotFunc recvSlot,
- const char* qof_type,
- QofEventId event_type)
+ const char* qof_type)
: m_receiver(receiver)
, m_receiveFunc(recvSlot)
, m_qof_type(qof_type)
- , m_event_type(event_type)
{
m_handler_id = qof_event_register_handler(QofEventWrapper::event_handler, this);
}
@@ -91,23 +89,22 @@
// correct event type
if (!QOF_CHECK_TYPE(entity, m_qof_type))
return;
- if ((event_type & m_event_type) == 0)
- return;
+// if ((event_type & m_event_type) == 0)
+// return;
- qDebug() << "private_event_handler, id=" << qofEventToString(event_type)
- << "entity=" << getQofType(entity);
+// qDebug() << "private_event_handler, id=" << qofEventToString(event_type)
+// << "entity=" << getQofType(entity);
ValuePtrT vptr = reinterpret_cast<ValuePtrT>(entity);
// Call the pointer-to-member function with that weird C++
// syntax
- (m_receiver.*m_receiveFunc)(vptr);
+ (m_receiver.*m_receiveFunc)(vptr, event_type);
}
ReceiverT& m_receiver;
SlotFunc m_receiveFunc;
const char* m_qof_type;
- QofEventId m_event_type;
gint m_handler_id;
};
Modified: gnucash/trunk/src/gnc/Split.cpp
===================================================================
--- gnucash/trunk/src/gnc/Split.cpp 2010-03-17 19:24:01 UTC (rev 18926)
+++ gnucash/trunk/src/gnc/Split.cpp 2010-03-17 21:28:51 UTC (rev 18927)
@@ -33,11 +33,33 @@
Account Split::getAccount() const { return xaccSplitGetAccount(get()); }
void Split::setAccount(Account& acc) { xaccSplitSetAccount(get(), acc.get()); }
+void Split::setAccount(::Account* acc) { xaccSplitSetAccount(get(), acc); }
Transaction Split::getParent() const { return xaccSplitGetParent(get()); }
void Split::setParent(Transaction& trans) { xaccSplitSetParent(get(), trans.get()); }
+TmpSplit::TmpSplit(const Split& s, const TmpTransaction* parent_trans)
+ : account(s.getAccount().get())
+ , parent(parent_trans)
+ , memo(s.getMemo())
+ , action(s.getAction())
+ , reconcile(s.getReconcile())
+ , amount(s.getAmount())
+ , value(s.getValue())
+{}
+void TmpSplit::copyInto(Transaction& t)
+{
+ Split s(xaccMallocSplit(t.getBook().get()));
+ s.setAccount(account);
+ s.setParent(t);
+ s.setMemo(memo);
+ s.setAction(action);
+ s.setReconcile(reconcile);
+ s.setAmount(amount);
+ s.setValue(value);
+}
+
} // END namespace gnc
Modified: gnucash/trunk/src/gnc/Split.hpp
===================================================================
--- gnucash/trunk/src/gnc/Split.hpp 2010-03-17 19:24:01 UTC (rev 18926)
+++ gnucash/trunk/src/gnc/Split.hpp 2010-03-17 21:28:51 UTC (rev 18927)
@@ -42,6 +42,7 @@
class Book;
class Account;
class Transaction;
+class TmpTransaction;
typedef QList< ::Split*> SplitQList;
@@ -64,6 +65,7 @@
Book getBook() const;
Account getAccount() const;
void setAccount(Account& acc);
+ void setAccount(::Account* acc);
Transaction getParent() const;
void setParent(Transaction& trans);
@@ -110,6 +112,22 @@
}
};
+class TmpSplit
+{
+public:
+ TmpSplit(const Split& s, const TmpTransaction* parent_trans);
+ TmpSplit()
+ {}
+ void copyInto(Transaction& t);
+ ::Account* account;
+ const TmpTransaction* parent;
+ QString memo;
+ QString action;
+ char reconcile;
+ Numeric amount;
+ Numeric value;
+};
+
} // END namespace gnc
#endif
Modified: gnucash/trunk/src/gnc/SplitListModel.cpp
===================================================================
--- gnucash/trunk/src/gnc/SplitListModel.cpp 2010-03-17 19:24:01 UTC (rev 18926)
+++ gnucash/trunk/src/gnc/SplitListModel.cpp 2010-03-17 21:28:51 UTC (rev 18927)
@@ -21,6 +21,7 @@
*/
#include "SplitListModel.hpp"
+#include "engine/gnc-event.h" // for GNC_EVENT_ITEM_ADDED
#include "gnc/Transaction.hpp"
#include "gnc/Cmd.hpp"
#include "gnc/Session.hpp"
@@ -39,16 +40,30 @@
SplitListModel::SplitListModel(const Account& acc, QUndoStack* undoStack, QObject *parent)
: QAbstractItemModel(parent)
, m_account(acc)
- , m_list(Split::fromGList(acc.getSplitList()))
+ , m_list()
, m_undoStack(undoStack)
- , m_eventWrapper(*this, &SplitListModel::transactionModified,
- GNC_ID_TRANS, QOF_EVENT_MODIFY)
+ , m_eventWrapper(*this, &SplitListModel::transactionEvent, GNC_ID_TRANS)
+ , m_eventWrapperAccount(*this, &SplitListModel::accountEvent, GNC_ID_ACCOUNT)
{
+ recreateCache();
+}
+
+void SplitListModel::recreateCache()
+{
+ SplitQList newSplits = Split::fromGList(m_account.getSplitList());
+ bool doReset = (newSplits.size() != m_list.size());
+
+ m_list = newSplits;
+
// Cache the mapping of transactions to split in the m_hash
+ m_hash.clear();
for (int k = 0; k < m_list.size(); ++k)
{
m_hash.insert(Split(m_list[k]).getParent().get(), k);
}
+
+ if (doReset)
+ reset();
}
SplitListModel::~SplitListModel()
@@ -72,6 +87,29 @@
return QModelIndex();
}
+bool SplitListModel::insertRows(int position, int rows, const QModelIndex &index)
+{
+ beginInsertRows(QModelIndex(), position, position + rows - 1);
+ endInsertRows();
+ return true;
+}
+
+bool SplitListModel::removeRows(int position, int rows, const QModelIndex &index)
+{
+ beginRemoveRows(QModelIndex(), position, position+rows-1);
+ for (int row = position; row < position + rows; ++row)
+ {
+ Split s(m_list.at(row));
+ Q_ASSERT(s);
+ Transaction t = s.getParent();
+ Q_ASSERT(t);
+ QUndoCommand* cmd = cmd::destroyTransaction(t);
+ m_undoStack->push(cmd);
+ }
+ endRemoveRows();
+ return true;
+}
+
int SplitListModel::columnCount(const QModelIndex& parent) const
{
//qDebug() << "columnCount()" << parent;
@@ -344,14 +382,39 @@
return false;
}
-void SplitListModel::transactionModified( ::Transaction* trans)
+void SplitListModel::transactionEvent( ::Transaction* trans, QofEventId event_type)
{
- if (m_hash.contains(trans))
+ qDebug() << "transactionEvent, id=" << qofEventToString(event_type);
+ switch (event_type)
{
- int row = m_hash.value(trans);
- emit dataChanged(index(row, 0), index(row, columnCount() - 1));
+ case QOF_EVENT_MODIFY:
+ if (m_hash.contains(trans))
+ {
+ int row = m_hash.value(trans);
+ emit dataChanged(index(row, 0), index(row, columnCount() - 1));
+ }
+ break;
+ default:
+ break;
}
}
+void SplitListModel::accountEvent( ::Account* acc, QofEventId event_type)
+{
+ if (acc != m_account.get())
+ return;
+ qDebug() << "accountEvent, id=" << qofEventToString(event_type);
+
+ switch (event_type)
+ {
+ case GNC_EVENT_ITEM_REMOVED:
+ case GNC_EVENT_ITEM_ADDED:
+ recreateCache();
+ break;
+ default:
+ break;
+ }
+}
+
} // END namespace gnc
Modified: gnucash/trunk/src/gnc/SplitListModel.hpp
===================================================================
--- gnucash/trunk/src/gnc/SplitListModel.hpp 2010-03-17 19:24:01 UTC (rev 18926)
+++ gnucash/trunk/src/gnc/SplitListModel.hpp 2010-03-17 21:28:51 UTC (rev 18927)
@@ -59,9 +59,15 @@
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
+ bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex());
+ bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex());
+
public slots:
- void transactionModified( ::Transaction* trans);
+ void transactionEvent( ::Transaction* trans, QofEventId event_type);
+ void accountEvent( ::Account* trans, QofEventId event_type);
+private:
+ void recreateCache();
protected:
Account m_account;
SplitQList m_list;
@@ -71,6 +77,7 @@
/** The wrapper for receiving events from gnc. */
QofEventWrapper<SplitListModel, ::Transaction*> m_eventWrapper;
+ QofEventWrapper<SplitListModel, ::Account*> m_eventWrapperAccount;
};
} // END namespace gnc
Modified: gnucash/trunk/src/gnc/Transaction.hpp
===================================================================
--- gnucash/trunk/src/gnc/Transaction.hpp 2010-03-17 19:24:01 UTC (rev 18926)
+++ gnucash/trunk/src/gnc/Transaction.hpp 2010-03-17 21:28:51 UTC (rev 18927)
@@ -58,6 +58,8 @@
: base_class(ptr)
{ }
+ Book getBook() const { return xaccTransGetBook(get()); }
+
void beginEdit() { xaccTransBeginEdit(get()); }
void commitEdit() { xaccTransCommitEdit(get()); }
void rollbackEdit() { xaccTransRollbackEdit(get()); }
@@ -78,7 +80,7 @@
void appendSplit(Split& split) { xaccSplitSetParent(split.get(), get()); }
Split getSplit(int i) const { return xaccTransGetSplit(get(), i); }
int getSplitIndex(const Split& split) const { return xaccTransGetSplitIndex(get(), split.get()); }
- SplitList* getSplitList() const { return xaccTransGetSplitList(get()); }
+ ::SplitList* getSplitList() const { return xaccTransGetSplitList(get()); }
Commodity getCurrency() const { return xaccTransGetCurrency(get()); }
void setCurrency(const Commodity& c) { xaccTransSetCurrency(get(), c.get()); }
@@ -94,6 +96,46 @@
};
+class TmpTransaction
+{
+public:
+ TmpTransaction(const Transaction& t)
+ : num(t.getNum())
+ , description(t.getDescription())
+ , notes(t.getNotes())
+ , commodity(t.getCurrency())
+ , datePosted(t.getDatePosted())
+ , dateTimeEntered(t.getDateEntered())
+ {
+ SplitQList slist = Split::fromGList(t.getSplitList());
+ Q_FOREACH(Split s, slist)
+ {
+ splits.push_back(TmpSplit(s, this));
+ }
+ }
+ void copyTo(Transaction& t)
+ {
+ t.setNum(num);
+ t.setDescription(description);
+ if (!notes.isEmpty())
+ t.setNotes(notes);
+ t.setCurrency(commodity);
+ t.setDatePosted(datePosted);
+ t.setDateEntered(dateTimeEntered);
+ Q_FOREACH(TmpSplit s, splits)
+ {
+ s.copyInto(t);
+ }
+ }
+ QString num;
+ QString description;
+ QString notes;
+ QList<TmpSplit> splits;
+ Commodity commodity;
+ QDate datePosted;
+ QDateTime dateTimeEntered;
+};
+
} // END namespace gnc
#endif
Modified: gnucash/trunk/src/gnc/mainwindow.cpp
===================================================================
--- gnucash/trunk/src/gnc/mainwindow.cpp 2010-03-17 19:24:01 UTC (rev 18926)
+++ gnucash/trunk/src/gnc/mainwindow.cpp 2010-03-17 21:28:51 UTC (rev 18927)
@@ -435,13 +435,46 @@
tableView->scrollToBottom();
if (smodel->rowCount() > 0)
tableView->setCurrentIndex(smodel->index(smodel->rowCount() - 1, 0));
+ ui->actionCut->setEnabled(smodel->rowCount() > 0);
// Insert this as a new tab
tableView->setProperty(PROPERTY_TAB_PREVIOUSPOS, ui->tabWidget->currentIndex());
ui->tabWidget->addTab(tableView, account.getName());
ui->tabWidget->setCurrentWidget(tableView);
+
+ connect(tableView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
+ this, SLOT(selectionChanged(const QItemSelection &, const QItemSelection & )));
}
+void MainWindow::selectionChanged(const QItemSelection & selected, const QItemSelection & deselected )
+{
+ ui->actionCut->setEnabled(!selected.isEmpty());
+ //ui->actionCopy->setEnabled(!selected.isEmpty());
+}
+
+// Auto-connected to actionCut's signal triggered()
+void MainWindow::on_actionCut_triggered()
+{
+ QWidget *widget = ui->tabWidget->currentWidget();
+ QTableView *tableView = qobject_cast<QTableView *>(widget);
+ if (tableView)
+ {
+// QModelIndexList selection = tableView->selectionModel()->selectedIndexes();
+// QSet<int> rows;
+// Q_FOREACH (QModelIndex index, selection)
+// {
+// rows.insert(index.row());
+// }
+// qDebug() << "Removing number of rows:" << rows.size();
+ QModelIndex index = tableView->currentIndex();
+ if (!index.isValid())
+ return;
+ QAbstractItemModel *model = tableView->model();
+ Q_ASSERT(model);
+ model->removeRow(index.row());
+ }
+}
+
// ////////////////////////////////////////////////////////////
void MainWindow::closeEvent(QCloseEvent *event)
Modified: gnucash/trunk/src/gnc/mainwindow.hpp
===================================================================
--- gnucash/trunk/src/gnc/mainwindow.hpp 2010-03-17 19:24:01 UTC (rev 18926)
+++ gnucash/trunk/src/gnc/mainwindow.hpp 2010-03-17 21:28:51 UTC (rev 18927)
@@ -24,6 +24,7 @@
#define MAINWINDOW_H
#include <QMainWindow>
+#include <QItemSelection>
#include "gnc/Session.hpp"
#include "gnc/AccountItemModel.hpp"
@@ -72,6 +73,7 @@
void on_actionAbout_triggered();
bool on_actionSave_as_triggered();
void on_actionCloseTab_triggered();
+ void on_actionCut_triggered();
void on_tabWidget_tabCloseRequested(int index);
void on_tabWidget_currentChanged(int index);
void on_textBrowser_anchorClicked(const QUrl &);
@@ -79,6 +81,7 @@
void on_actionViewAccountList_triggered(bool checked);
void on_actionViewWelcomepage_triggered(bool checked);
void documentWasModified();
+ void selectionChanged(const QItemSelection & selected, const QItemSelection & deselected );
private:
void createActions();
More information about the gnucash-changes
mailing list