From 76af4eb876814a916dd4f26cf71faa20bdc54f2d Mon Sep 17 00:00:00 2001
From: Jonas Schnelli <dev@jonasschnelli.ch>
Date: Fri, 18 Nov 2016 10:26:38 +0100
Subject: [PATCH 1/2] [Qt] fix coincontrol sort issue

---
 src/qt/coincontroldialog.cpp | 21 +++++++++++++++------
 src/qt/coincontroldialog.h   | 12 ++++++++++++
 2 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 1a1671f0e..42a32a1a2 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -35,6 +35,15 @@ QList<CAmount> CoinControlDialog::payAmounts;
 CCoinControl* CoinControlDialog::coinControl = new CCoinControl();
 bool CoinControlDialog::fSubtractFeeFromAmount = false;
 
+bool CCoinControlWidgetItem::operator<(const QTreeWidgetItem &other) const {
+    int column = treeWidget()->sortColumn();
+    if (column == CoinControlDialog::COLUMN_AMOUNT_INT64 || column == CoinControlDialog::COLUMN_AMOUNT_INT64)
+        return data(CoinControlDialog::COLUMN_AMOUNT_INT64, Qt::DisplayRole).toULongLong() < other.data(CoinControlDialog::COLUMN_AMOUNT_INT64, Qt::DisplayRole).toULongLong();
+    if (column == CoinControlDialog::COLUMN_DATE || column == CoinControlDialog::COLUMN_DATE_INT64)
+        return data(CoinControlDialog::COLUMN_DATE_INT64, Qt::DisplayRole).toULongLong() < other.data(CoinControlDialog::COLUMN_DATE_INT64, Qt::DisplayRole).toULongLong();
+    return QTreeWidgetItem::operator<(other);
+}
+
 CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
     QDialog(parent),
     ui(new Ui::CoinControlDialog),
@@ -658,7 +667,7 @@ void CoinControlDialog::updateView()
     model->listCoins(mapCoins);
 
     BOOST_FOREACH(const PAIRTYPE(QString, std::vector<COutput>)& coins, mapCoins) {
-        QTreeWidgetItem *itemWalletAddress = new QTreeWidgetItem();
+        CCoinControlWidgetItem *itemWalletAddress = new CCoinControlWidgetItem();
         itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
         QString sWalletAddress = coins.first;
         QString sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress);
@@ -686,9 +695,9 @@ void CoinControlDialog::updateView()
             nSum += out.tx->vout[out.i].nValue;
             nChildren++;
 
-            QTreeWidgetItem *itemOutput;
-            if (treeMode)    itemOutput = new QTreeWidgetItem(itemWalletAddress);
-            else             itemOutput = new QTreeWidgetItem(ui->treeWidget);
+            CCoinControlWidgetItem *itemOutput;
+            if (treeMode)    itemOutput = new CCoinControlWidgetItem(itemWalletAddress);
+            else             itemOutput = new CCoinControlWidgetItem(ui->treeWidget);
             itemOutput->setFlags(flgCheckbox);
             itemOutput->setCheckState(COLUMN_CHECKBOX,Qt::Unchecked);
 
@@ -721,11 +730,11 @@ void CoinControlDialog::updateView()
 
             // amount
             itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.tx->vout[out.i].nValue));
-            itemOutput->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(out.tx->vout[out.i].nValue), 15, " ")); // padding so that sorting works correctly
+            itemOutput->setData(COLUMN_AMOUNT_INT64, Qt::DisplayRole, QVariant((qlonglong)out.tx->vout[out.i].nValue)); // padding so that sorting works correctly
 
             // date
             itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime()));
-            itemOutput->setText(COLUMN_DATE_INT64, strPad(QString::number(out.tx->GetTxTime()), 20, " "));
+            itemOutput->setData(COLUMN_DATE_INT64, Qt::DisplayRole, QVariant((qlonglong)out.tx->GetTxTime()));
 
             // confirmations
             itemOutput->setText(COLUMN_CONFIRMATIONS, strPad(QString::number(out.nDepth), 8, " "));
diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h
index 7d73421e3..960e92f79 100644
--- a/src/qt/coincontroldialog.h
+++ b/src/qt/coincontroldialog.h
@@ -28,6 +28,17 @@ namespace Ui {
 
 #define ASYMP_UTF8 "\xE2\x89\x88"
 
+class CCoinControlWidgetItem : public QTreeWidgetItem
+{
+public:
+    CCoinControlWidgetItem(QTreeWidget *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
+    CCoinControlWidgetItem(int type = Type) : QTreeWidgetItem(type) {}
+    CCoinControlWidgetItem(QTreeWidgetItem *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
+
+    bool operator<(const QTreeWidgetItem &other) const;
+};
+
+
 class CoinControlDialog : public QDialog
 {
     Q_OBJECT
@@ -76,6 +87,7 @@ private:
         COLUMN_AMOUNT_INT64,
         COLUMN_DATE_INT64
     };
+    friend class CCoinControlWidgetItem;
 
     // some columns have a hidden column containing the value used for sorting
     int getMappedColumn(int column, bool fVisibleColumn = true)

From 4231032bfcb9728f0f629b3d67884ba9de63e4ff Mon Sep 17 00:00:00 2001
From: "Wladimir J. van der Laan" <laanwj@gmail.com>
Date: Fri, 18 Nov 2016 14:33:34 +0100
Subject: [PATCH 2/2] [Qt] Clean up and fix coincontrol tree widget handling

- Do sorting for date, amount and confirmations column as longlong, not
  unsigned longlong.
- Use `UserRole` to store our own data. This makes it treated as
  ancillary data prevents it from being displayed.
- Get rid of `getMappedColumn` `strPad` - these are no longer necessary.
- Get rid of hidden `_INT64` columns.
- Start enumeration from 0 (otherwise values are undefined).
---
 src/qt/coincontroldialog.cpp | 34 ++++++++++------------------------
 src/qt/coincontroldialog.h   | 26 +-------------------------
 2 files changed, 11 insertions(+), 49 deletions(-)

diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 42a32a1a2..1010a62fc 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -37,10 +37,8 @@ bool CoinControlDialog::fSubtractFeeFromAmount = false;
 
 bool CCoinControlWidgetItem::operator<(const QTreeWidgetItem &other) const {
     int column = treeWidget()->sortColumn();
-    if (column == CoinControlDialog::COLUMN_AMOUNT_INT64 || column == CoinControlDialog::COLUMN_AMOUNT_INT64)
-        return data(CoinControlDialog::COLUMN_AMOUNT_INT64, Qt::DisplayRole).toULongLong() < other.data(CoinControlDialog::COLUMN_AMOUNT_INT64, Qt::DisplayRole).toULongLong();
-    if (column == CoinControlDialog::COLUMN_DATE || column == CoinControlDialog::COLUMN_DATE_INT64)
-        return data(CoinControlDialog::COLUMN_DATE_INT64, Qt::DisplayRole).toULongLong() < other.data(CoinControlDialog::COLUMN_DATE_INT64, Qt::DisplayRole).toULongLong();
+    if (column == CoinControlDialog::COLUMN_AMOUNT || column == CoinControlDialog::COLUMN_DATE || column == CoinControlDialog::COLUMN_CONFIRMATIONS)
+        return data(column, Qt::UserRole).toLongLong() < other.data(column, Qt::UserRole).toLongLong();
     return QTreeWidgetItem::operator<(other);
 }
 
@@ -137,11 +135,9 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidge
     ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 110);
     ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true);         // store transaction hash in this column, but don't show it
     ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true);     // store vout index in this column, but don't show it
-    ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true);   // store amount int64 in this column, but don't show it
-    ui->treeWidget->setColumnHidden(COLUMN_DATE_INT64, true);     // store date int64 in this column, but don't show it
 
     // default view is sorted by amount desc
-    sortView(COLUMN_AMOUNT_INT64, Qt::DescendingOrder);
+    sortView(COLUMN_AMOUNT, Qt::DescendingOrder);
 
     // restore list mode and sortorder as a convenience feature
     QSettings settings;
@@ -173,15 +169,6 @@ void CoinControlDialog::setModel(WalletModel *_model)
     }
 }
 
-// helper function str_pad
-QString CoinControlDialog::strPad(QString s, int nPadLength, QString sPadding)
-{
-    while (s.length() < nPadLength)
-        s = sPadding + s;
-
-    return s;
-}
-
 // ok button
 void CoinControlDialog::buttonBoxClicked(QAbstractButton* button)
 {
@@ -347,7 +334,7 @@ void CoinControlDialog::sortView(int column, Qt::SortOrder order)
     sortColumn = column;
     sortOrder = order;
     ui->treeWidget->sortItems(column, order);
-    ui->treeWidget->header()->setSortIndicator(getMappedColumn(sortColumn), sortOrder);
+    ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder);
 }
 
 // treeview: clicked on header
@@ -355,12 +342,10 @@ void CoinControlDialog::headerSectionClicked(int logicalIndex)
 {
     if (logicalIndex == COLUMN_CHECKBOX) // click on most left column -> do nothing
     {
-        ui->treeWidget->header()->setSortIndicator(getMappedColumn(sortColumn), sortOrder);
+        ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder);
     }
     else
     {
-        logicalIndex = getMappedColumn(logicalIndex, false);
-
         if (sortColumn == logicalIndex)
             sortOrder = ((sortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder);
         else
@@ -730,14 +715,15 @@ void CoinControlDialog::updateView()
 
             // amount
             itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.tx->vout[out.i].nValue));
-            itemOutput->setData(COLUMN_AMOUNT_INT64, Qt::DisplayRole, QVariant((qlonglong)out.tx->vout[out.i].nValue)); // padding so that sorting works correctly
+            itemOutput->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)out.tx->vout[out.i].nValue)); // padding so that sorting works correctly
 
             // date
             itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime()));
-            itemOutput->setData(COLUMN_DATE_INT64, Qt::DisplayRole, QVariant((qlonglong)out.tx->GetTxTime()));
+            itemOutput->setData(COLUMN_DATE, Qt::UserRole, QVariant((qlonglong)out.tx->GetTxTime()));
 
             // confirmations
-            itemOutput->setText(COLUMN_CONFIRMATIONS, strPad(QString::number(out.nDepth), 8, " "));
+            itemOutput->setText(COLUMN_CONFIRMATIONS, QString::number(out.nDepth));
+            itemOutput->setData(COLUMN_CONFIRMATIONS, Qt::UserRole, QVariant((qlonglong)out.nDepth));
 
             // transaction hash
             uint256 txhash = out.tx->GetHash();
@@ -765,7 +751,7 @@ void CoinControlDialog::updateView()
         {
             itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")");
             itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum));
-            itemWalletAddress->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(nSum), 15, " "));
+            itemWalletAddress->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)nSum));
         }
     }
 
diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h
index 960e92f79..7c2269b1e 100644
--- a/src/qt/coincontroldialog.h
+++ b/src/qt/coincontroldialog.h
@@ -70,13 +70,12 @@ private:
 
     const PlatformStyle *platformStyle;
 
-    QString strPad(QString, int, QString);
     void sortView(int, Qt::SortOrder);
     void updateView();
 
     enum
     {
-        COLUMN_CHECKBOX,
+        COLUMN_CHECKBOX = 0,
         COLUMN_AMOUNT,
         COLUMN_LABEL,
         COLUMN_ADDRESS,
@@ -84,32 +83,9 @@ private:
         COLUMN_CONFIRMATIONS,
         COLUMN_TXHASH,
         COLUMN_VOUT_INDEX,
-        COLUMN_AMOUNT_INT64,
-        COLUMN_DATE_INT64
     };
     friend class CCoinControlWidgetItem;
 
-    // some columns have a hidden column containing the value used for sorting
-    int getMappedColumn(int column, bool fVisibleColumn = true)
-    {
-        if (fVisibleColumn)
-        {
-            if (column == COLUMN_AMOUNT_INT64)
-                return COLUMN_AMOUNT;
-            else if (column == COLUMN_DATE_INT64)
-                return COLUMN_DATE;
-        }
-        else
-        {
-            if (column == COLUMN_AMOUNT)
-                return COLUMN_AMOUNT_INT64;
-            else if (column == COLUMN_DATE)
-                return COLUMN_DATE_INT64;
-        }
-
-        return column;
-    }
-
 private Q_SLOTS:
     void showMenu(const QPoint &);
     void copyAmount();