Export functionality for transaction list
[novacoin.git] / src / qt / addresstablemodel.cpp
1 #include "addresstablemodel.h"
2 #include "guiutil.h"
3
4 #include "headers.h"
5
6 #include <QFont>
7 #include <QColor>
8
9 const QString AddressTableModel::Send = "S";
10 const QString AddressTableModel::Receive = "R";
11
12 struct AddressTableEntry
13 {
14     enum Type {
15         Sending,
16         Receiving
17     };
18
19     Type type;
20     QString label;
21     QString address;
22
23     AddressTableEntry() {}
24     AddressTableEntry(Type type, const QString &label, const QString &address):
25         type(type), label(label), address(address) {}
26 };
27
28 // Private implementation
29 struct AddressTablePriv
30 {
31     CWallet *wallet;
32     QList<AddressTableEntry> cachedAddressTable;
33
34     AddressTablePriv(CWallet *wallet):
35             wallet(wallet) {}
36
37     void refreshAddressTable()
38     {
39         cachedAddressTable.clear();
40
41         CRITICAL_BLOCK(wallet->cs_mapKeys)
42         CRITICAL_BLOCK(wallet->cs_mapAddressBook)
43         {
44             BOOST_FOREACH(const PAIRTYPE(std::string, std::string)& item, wallet->mapAddressBook)
45             {
46                 std::string strAddress = item.first;
47                 std::string strName = item.second;
48                 uint160 hash160;
49                 bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
50                 cachedAddressTable.append(AddressTableEntry(fMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending,
51                                   QString::fromStdString(strName),
52                                   QString::fromStdString(strAddress)));
53             }
54         }
55     }
56
57     int size()
58     {
59         return cachedAddressTable.size();
60     }
61
62     AddressTableEntry *index(int idx)
63     {
64         if(idx >= 0 && idx < cachedAddressTable.size())
65         {
66             return &cachedAddressTable[idx];
67         }
68         else
69         {
70             return 0;
71         }
72     }
73 };
74
75 AddressTableModel::AddressTableModel(CWallet *wallet, QObject *parent) :
76     QAbstractTableModel(parent),wallet(wallet),priv(0)
77 {
78     columns << tr("Label") << tr("Address");
79     priv = new AddressTablePriv(wallet);
80     priv->refreshAddressTable();
81 }
82
83 AddressTableModel::~AddressTableModel()
84 {
85     delete priv;
86 }
87
88 int AddressTableModel::rowCount(const QModelIndex &parent) const
89 {
90     Q_UNUSED(parent);
91     return priv->size();
92 }
93
94 int AddressTableModel::columnCount(const QModelIndex &parent) const
95 {
96     Q_UNUSED(parent);
97     return columns.length();
98 }
99
100 QVariant AddressTableModel::data(const QModelIndex &index, int role) const
101 {
102     if(!index.isValid())
103         return QVariant();
104
105     AddressTableEntry *rec = static_cast<AddressTableEntry*>(index.internalPointer());
106
107     if(role == Qt::DisplayRole || role == Qt::EditRole)
108     {
109         switch(index.column())
110         {
111         case Label:
112             if(rec->label.isEmpty() && role == Qt::DisplayRole)
113             {
114                 return tr("(no label)");
115             }
116             else
117             {
118                 return rec->label;
119             }
120         case Address:
121             return rec->address;
122         }
123     }
124     else if (role == Qt::FontRole)
125     {
126         QFont font;
127         if(index.column() == Address)
128         {
129             font = GUIUtil::bitcoinAddressFont();
130         }
131         return font;
132     }
133     else if (role == TypeRole)
134     {
135         switch(rec->type)
136         {
137         case AddressTableEntry::Sending:
138             return Send;
139         case AddressTableEntry::Receiving:
140             return Receive;
141         default: break;
142         }
143     }
144     return QVariant();
145 }
146
147 bool AddressTableModel::setData(const QModelIndex & index, const QVariant & value, int role)
148 {
149     if(!index.isValid())
150         return false;
151     AddressTableEntry *rec = static_cast<AddressTableEntry*>(index.internalPointer());
152
153     if(role == Qt::EditRole)
154     {
155         switch(index.column())
156         {
157         case Label:
158             wallet->SetAddressBookName(rec->address.toStdString(), value.toString().toStdString());
159             rec->label = value.toString();
160             break;
161         case Address:
162             // Refuse to set invalid address
163             if(!validateAddress(value.toString()))
164                 return false;
165             // Double-check that we're not overwriting receiving address
166             if(rec->type == AddressTableEntry::Sending)
167             {
168                 // Remove old entry
169                 wallet->EraseAddressBookName(rec->address.toStdString());
170                 // Add new entry with new address
171                 wallet->SetAddressBookName(value.toString().toStdString(), rec->label.toStdString());
172
173                 rec->address = value.toString();
174             }
175             break;
176         }
177         emit dataChanged(index, index);
178
179         return true;
180     }
181     return false;
182 }
183
184 QVariant AddressTableModel::headerData(int section, Qt::Orientation orientation, int role) const
185 {
186     if(orientation == Qt::Horizontal)
187     {
188         if(role == Qt::DisplayRole)
189         {
190             return columns[section];
191         }
192     }
193     return QVariant();
194 }
195
196 Qt::ItemFlags AddressTableModel::flags(const QModelIndex & index) const
197 {
198     if(!index.isValid())
199         return 0;
200     AddressTableEntry *rec = static_cast<AddressTableEntry*>(index.internalPointer());
201
202     Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
203     // Can edit address and label for sending addresses,
204     // and only label for receiving addresses.
205     if(rec->type == AddressTableEntry::Sending ||
206       (rec->type == AddressTableEntry::Receiving && index.column()==Label))
207     {
208         retval |= Qt::ItemIsEditable;
209     }
210     return retval;
211 }
212
213 QModelIndex AddressTableModel::index(int row, int column, const QModelIndex & parent) const
214 {
215     Q_UNUSED(parent);
216     AddressTableEntry *data = priv->index(row);
217     if(data)
218     {
219         return createIndex(row, column, priv->index(row));
220     }
221     else
222     {
223         return QModelIndex();
224     }
225 }
226
227 void AddressTableModel::updateList()
228 {
229     // Update internal model from Bitcoin core
230     beginResetModel();
231     priv->refreshAddressTable();
232     endResetModel();
233 }
234
235 QString AddressTableModel::addRow(const QString &type, const QString &label, const QString &address)
236 {
237     std::string strLabel = label.toStdString();
238     std::string strAddress = address.toStdString();
239
240     if(type == Send)
241     {
242         // Check for duplicate
243         CRITICAL_BLOCK(wallet->cs_mapAddressBook)
244         {
245             if(wallet->mapAddressBook.count(strAddress))
246             {
247                 return QString();
248             }
249         }
250     }
251     else if(type == Receive)
252     {
253         // Generate a new address to associate with given label, optionally
254         // set as default receiving address.
255         strAddress = PubKeyToAddress(wallet->GetKeyFromKeyPool());
256     }
257     else
258     {
259         return QString();
260     }
261     // Add entry and update list
262     wallet->SetAddressBookName(strAddress, strLabel);
263     updateList();
264     return QString::fromStdString(strAddress);
265 }
266
267 bool AddressTableModel::removeRows(int row, int count, const QModelIndex & parent)
268 {
269     Q_UNUSED(parent);
270     AddressTableEntry *rec = priv->index(row);
271     if(count != 1 || !rec || rec->type == AddressTableEntry::Receiving)
272     {
273         // Can only remove one row at a time, and cannot remove rows not in model.
274         // Also refuse to remove receiving addresses.
275         return false;
276     }
277     wallet->EraseAddressBookName(rec->address.toStdString());
278     updateList();
279     return true;
280 }
281
282 void AddressTableModel::update()
283 {
284
285 }
286
287 bool AddressTableModel::validateAddress(const QString &address)
288 {
289     uint160 hash160 = 0;
290
291     return AddressToHash160(address.toStdString(), hash160);
292 }