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