1 //  This file is part of Qt Bitcoin Trader
2 //      https://github.com/JulyIGHOR/QtBitcoinTrader
3 //  Copyright (C) 2013-2021 July Ighor <julyighor@gmail.com>
4 //
5 //  This program is free software: you can redistribute it and/or modify
6 //  it under the terms of the GNU General Public License as published by
7 //  the Free Software Foundation, either version 3 of the License, or
8 //  (at your option) any later version.
9 //
10 //  In addition, as a special exception, the copyright holders give
11 //  permission to link the code of portions of this program with the
12 //  OpenSSL library under certain conditions as described in each
13 //  individual source file, and distribute linked combinations including
14 //  the two.
15 //
16 //  You must obey the GNU General Public License in all respects for all
17 //  of the code used other than OpenSSL. If you modify file(s) with this
18 //  exception, you may extend this exception to your version of the
19 //  file(s), but you are not obligated to do so. If you do not wish to do
20 //  so, delete this exception statement from your version. If you delete
21 //  this exception statement from all source files in the program, then
22 //  also delete it here.
23 //
24 //  This program is distributed in the hope that it will be useful,
25 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
26 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27 //  GNU General Public License for more details.
28 //
29 //  You should have received a copy of the GNU General Public License
30 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
31 
32 #include "historymodel.h"
33 #include "main.h"
34 
HistoryModel()35 HistoryModel::HistoryModel()
36     : QAbstractItemModel()
37 {
38     typeWidth = 75;
39     columnsCount = 7;
40     lastDate = 0;
41     typesLabels << "" << "Bought" << "Sell" << "Buy" << "Fee" << "Deposit" <<
42                 "Withdraw"; //0=General, 1=Sell, 2=Buy, 3=Fee, 4=Deposit, 5=Withdraw
43 }
44 
~HistoryModel()45 HistoryModel::~HistoryModel()
46 {
47 
48 }
49 
clear()50 void HistoryModel::clear()
51 {
52     if (itemsList.isEmpty())
53         return;
54 
55     beginResetModel();
56     lastDate = 0;
57     itemsList.clear();
58     endResetModel();
59 }
60 
loadLastPrice()61 void HistoryModel::loadLastPrice()
62 {
63     bool haveLastBuy = false;
64     bool haveLastSell = false;
65 
66     for (int n = 0; n < itemsList.size(); n++)
67         if (itemsList.at(n).symbol == baseValues.currentPair.symbol)
68         {
69             if (!haveLastSell && itemsList.at(n).type == 1)
70             {
71                 emit accLastSellChanged(itemsList.at(n).symbol.right(3), itemsList.at(n).price);
72                 haveLastSell = true;
73             }
74 
75             if (!haveLastBuy && itemsList.at(n).type == 2)
76             {
77                 emit accLastBuyChanged(itemsList.at(n).symbol.right(3), itemsList.at(n).price);
78                 haveLastBuy = true;
79             }
80 
81             if (haveLastSell && haveLastBuy)
82                 break;
83         }
84 }
85 
historyChanged(QList<HistoryItem> * histList)86 void HistoryModel::historyChanged(QList<HistoryItem>* histList)
87 {
88     bool haveLastBuy = false;
89     bool haveLastSell = false;
90 
91     for (int n = 0; n < histList->size(); n++)
92         if (histList->at(n).symbol == baseValues.currentPair.symbol)
93         {
94             if (!haveLastSell && histList->at(n).type == 1)
95             {
96                 emit accLastSellChanged(histList->at(n).symbol.right(3), histList->at(n).price);
97                 haveLastSell = true;
98             }
99 
100             if (!haveLastBuy && histList->at(n).type == 2)
101             {
102                 emit accLastBuyChanged(histList->at(n).symbol.right(3), histList->at(n).price);
103                 haveLastBuy = true;
104             }
105 
106             if (haveLastSell && haveLastBuy)
107                 break;
108         }
109 
110     while (!histList->empty() && histList->last().dateTimeInt <= lastDate)
111         histList->removeLast();
112 
113     if (histList->empty())
114     {
115         delete histList;
116         return;
117     }
118 
119     beginInsertRows(QModelIndex(), 0, histList->size() - 1);
120 
121     if (!histList->empty() && !itemsList.empty())
122     {
123         (*histList)[histList->size() - 1].displayFullDate = histList->at(histList->size() - 1).dateInt !=
124                 itemsList.last().dateInt;
125     }
126 
127     if (itemsList.isEmpty() && !histList->empty())
128         (*histList)[histList->size() - 1].displayFullDate = true;
129 
130     qint64 maxListDate = 0;
131 
132     for (int n = histList->size() - 1; n >= 0; n--)
133     {
134         if (maxListDate < histList->at(n).dateTimeInt)
135             maxListDate = histList->at(n).dateTimeInt;
136 
137         if (n != histList->size() - 1)
138             (*histList)[n].displayFullDate = histList->at(n).dateInt != histList->at(n + 1).dateInt;
139 
140         itemsList << histList->at(n);
141 
142         static QMap<QString, quint32> lastDateMap;
143 
144         if (lastDateMap.value(itemsList.last().symbol, 0UL) <= itemsList.last().dateInt)
145         {
146             lastDateMap[itemsList.last().symbol] = itemsList.last().dateInt;
147             mainWindow.sendIndicatorEvent(itemsList.last().symbol + itemsList.last().currRequestSecond,
148                                           QLatin1String("MyLastTrade"), itemsList.last().volume);
149         }
150     }
151 
152     delete histList;
153 
154     if (maxListDate > lastDate)
155         lastDate = maxListDate;
156 
157     endInsertRows();
158 }
159 
getRowPrice(int row)160 double HistoryModel::getRowPrice(int row)
161 {
162     row = itemsList.size() - row - 1;
163 
164     if (row < 0 || row >= itemsList.size())
165         return 0.0;
166 
167     return itemsList.at(row).price;
168 }
169 
getRowVolume(int row)170 double HistoryModel::getRowVolume(int row)
171 {
172     row = itemsList.size() - row - 1;
173 
174     if (row < 0 || row >= itemsList.size())
175         return 0.0;
176 
177     return itemsList.at(row).volume;
178 }
179 
getRowType(int row)180 int HistoryModel::getRowType(int row)
181 {
182     row = itemsList.size() - row - 1;
183 
184     if (row < 0 || row >= itemsList.size())
185         return 0.0;
186 
187     return itemsList.at(row).type;
188 }
189 
rowCount(const QModelIndex &) const190 int HistoryModel::rowCount(const QModelIndex& /*parent*/) const
191 {
192     return itemsList.size();
193 }
194 
columnCount(const QModelIndex &) const195 int HistoryModel::columnCount(const QModelIndex& /*parent*/) const
196 {
197     return columnsCount;
198 }
199 
data(const QModelIndex & index,int role) const200 QVariant HistoryModel::data(const QModelIndex& index, int role) const
201 {
202     int currentRow = itemsList.size() - index.row() - 1;
203 
204     if (currentRow < 0 || currentRow >= itemsList.size())
205         return QVariant();
206 
207     if (role == Qt::WhatsThisRole)
208     {
209         return itemsList.at(currentRow).dateTimeStr + " " + typesLabels.at(itemsList.at(currentRow).type) + " " + itemsList.at(
210                    currentRow).priceStr + " " + itemsList.at(currentRow).totalStr;
211     }
212 
213     if (role == Qt::StatusTipRole)
214     {
215         return itemsList.at(currentRow).dateTimeStr + "\t" + itemsList.at(currentRow).volumeStr + "\t" + typesLabels.at(
216                    itemsList.at(currentRow).type) + "\t" + itemsList.at(currentRow).priceStr + "\t" + itemsList.at(currentRow).totalStr;
217     }
218 
219     if (role != Qt::DisplayRole && role != Qt::ToolTipRole && role != Qt::ForegroundRole && role != Qt::TextAlignmentRole)
220         return QVariant();
221 
222     int indexColumn = index.column();
223 
224     if (role == Qt::TextAlignmentRole)
225     {
226         if (indexColumn == 1)
227             return 0x0082;
228 
229         if (indexColumn == 2)
230             return 0x0082;
231 
232         if (indexColumn == 4)
233             return 0x0081;
234 
235         if (indexColumn == 5)
236             return 0x0082;
237 
238         if (indexColumn == 6)
239             return 0x0081;
240 
241         return 0x0084;
242     }
243 
244     if (role == Qt::ForegroundRole)
245     {
246         switch (indexColumn)
247         {
248         case 1:
249             return baseValues.appTheme.gray;
250             break;
251 
252         case 3:
253             switch (itemsList.at(currentRow).type)
254             {
255             case 1:
256                 return baseValues.appTheme.red;
257 
258             case 2:
259                 return baseValues.appTheme.blue;
260 
261             case 3:
262                 return baseValues.appTheme.darkGreen;
263 
264             case 4:
265                 return baseValues.appTheme.darkRed;
266 
267             case 5:
268                 return baseValues.appTheme.darkRedBlue;
269 
270             default:
271                 break;
272             }
273 
274             break;
275 
276         case 6:
277             return baseValues.appTheme.gray;
278             break;
279 
280         default:
281             break;
282         }
283 
284         return baseValues.appTheme.black;
285     }
286 
287     switch (indexColumn)
288     {
289     case 1:
290     {
291         //Date
292         if (role == Qt::ToolTipRole || itemsList.at(currentRow).displayFullDate)
293             return itemsList.at(currentRow).dateTimeStr;//DateTime
294 
295         return itemsList.at(currentRow).timeStr;//Time
296     }
297 
298     case 2:
299         return itemsList.at(currentRow).volumeStr;//Volume
300 
301     case 3:
302         return typesLabels.at(itemsList.at(currentRow).type);//Type
303 
304     case 4:
305         return itemsList.at(currentRow).priceStr;//Price
306 
307     case 5:
308         return itemsList.at(currentRow).totalStr;//Total
309 
310     case 6:
311         return itemsList.at(currentRow).description;//Description
312 
313     default:
314         break;
315     }
316 
317     return QVariant();
318 }
319 
headerData(int section,Qt::Orientation orientation,int role) const320 QVariant HistoryModel::headerData(int section, Qt::Orientation orientation, int role) const
321 {
322     if (orientation != Qt::Horizontal)
323         return QVariant();
324 
325     if (role == Qt::TextAlignmentRole)
326     {
327         if (section == 2)
328             return 0x0082;
329 
330         if (section == 4)
331             return 0x0081;
332 
333         return 0x0084;
334     }
335 
336     if (role == Qt::SizeHintRole)
337     {
338         switch (section)
339         {
340         case 1:
341             return QSize(dateWidth, defaultHeightForRow); //Date
342 
343         case 3:
344             return QSize(typeWidth, defaultHeightForRow); //Type
345         }
346 
347         return QVariant();
348     }
349 
350     if (role != Qt::DisplayRole)
351         return QVariant();
352 
353     if (headerLabels.size() != columnsCount)
354         return QVariant();
355 
356     return headerLabels.at(section);
357 }
358 
359 
flags(const QModelIndex &) const360 Qt::ItemFlags HistoryModel::flags(const QModelIndex& /*index*/) const
361 {
362     return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
363 }
364 
setHorizontalHeaderLabels(QStringList list)365 void HistoryModel::setHorizontalHeaderLabels(QStringList list)
366 {
367     if (list.size() != columnsCount)
368         return;
369 
370     typesLabels[1] = julyTr("LOG_SOLD", "sold");
371     typesLabels[2] = julyTr("LOG_BOUGHT", "bought");
372     typesLabels[3] = julyTr("LOG_FEE", "fee");
373     typesLabels[4] = julyTr("LOG_DEPOSIT", "deposit");
374     typesLabels[5] = julyTr("LOG_WITHDRAW", "withdraw");
375 
376     typeWidth = 0;
377 
378     for (int n = 1; n < typesLabels.size(); n++)
379         typeWidth = qMax(typeWidth, textFontWidth(typesLabels.at(n)));
380 
381     typeWidth = qMax(typeWidth, textFontWidth(list.at(2)));
382     typeWidth += 10;
383 
384     dateWidth = qMax(qMax(textFontWidth(QDateTime(QDate(2000, 12, 30), QTime(23, 59, 59,
385                                         999)).toString(baseValues.dateTimeFormat)), textFontWidth(QDateTime(QDate(2000, 12, 30), QTime(12, 59, 59,
386                                                 999)).toString(baseValues.dateTimeFormat))), textFontWidth(list.at(0))) + 10;
387 
388     headerLabels = list;
389     emit headerDataChanged(Qt::Horizontal, 0, columnsCount - 1);
390 }
391 
index(int row,int column,const QModelIndex & parent) const392 QModelIndex HistoryModel::index(int row, int column, const QModelIndex& parent) const
393 {
394     if (!hasIndex(row, column, parent))
395         return QModelIndex();
396 
397     return createIndex(row, column);
398 }
399 
parent(const QModelIndex &) const400 QModelIndex HistoryModel::parent(const QModelIndex& /*child*/) const
401 {
402     return QModelIndex();
403 }
404