mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Cutecash: Add deletion of rows/transactions (through "Cut"). With Undo. Hee Hee.
git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@18927 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
4e3be7b89c
commit
07d25ab17b
@ -178,6 +178,53 @@ QUndoCommand* setTransactionDate(Transaction& t, const QDate& newValue)
|
||||
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
|
||||
|
||||
|
@ -166,6 +166,7 @@ QUndoCommand* setTransactionDescription(Transaction& t, const QString& newValue)
|
||||
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
|
||||
|
||||
|
@ -52,18 +52,16 @@ inline const char* getQofType(QofInstance* obj)
|
||||
* 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 @@ private:
|
||||
// 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;
|
||||
};
|
||||
|
||||
|
@ -33,11 +33,33 @@ Book Split::getBook() const { return xaccSplitGetBook(get()); }
|
||||
|
||||
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
|
||||
|
@ -42,6 +42,7 @@ namespace gnc
|
||||
class Book;
|
||||
class Account;
|
||||
class Transaction;
|
||||
class TmpTransaction;
|
||||
|
||||
typedef QList< ::Split*> SplitQList;
|
||||
|
||||
@ -64,6 +65,7 @@ public:
|
||||
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 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
|
@ -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 @@ namespace gnc
|
||||
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 @@ QModelIndex SplitListModel::index(int row, int column,
|
||||
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 @@ bool SplitListModel::setData(const QModelIndex &index, const QVariant &value, in
|
||||
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
|
||||
|
@ -59,9 +59,15 @@ public:
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role);
|
||||
|
||||
public slots:
|
||||
void transactionModified( ::Transaction* trans);
|
||||
bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex());
|
||||
bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex());
|
||||
|
||||
public slots:
|
||||
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 @@ protected:
|
||||
|
||||
/** The wrapper for receiving events from gnc. */
|
||||
QofEventWrapper<SplitListModel, ::Transaction*> m_eventWrapper;
|
||||
QofEventWrapper<SplitListModel, ::Account*> m_eventWrapperAccount;
|
||||
};
|
||||
|
||||
} // END namespace gnc
|
||||
|
@ -58,6 +58,8 @@ public:
|
||||
: 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 @@ public:
|
||||
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 @@ public:
|
||||
|
||||
};
|
||||
|
||||
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
|
||||
|
@ -435,11 +435,44 @@ void MainWindow::accountItemActivated(const QModelIndex & index)
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
// ////////////////////////////////////////////////////////////
|
||||
|
@ -24,6 +24,7 @@
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QItemSelection>
|
||||
#include "gnc/Session.hpp"
|
||||
#include "gnc/AccountItemModel.hpp"
|
||||
|
||||
@ -72,6 +73,7 @@ private slots:
|
||||
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 @@ private slots:
|
||||
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();
|
||||
|
Loading…
Reference in New Issue
Block a user