KissCount

KissCount Git Source Tree

Root/src/view/StatsPanel.cpp

1/*
2 Copyright 2010-2012 Grégory Soutadé
3
4 This file is part of KissCount.
5
6 KissCount is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 KissCount is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with KissCount. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include <QMessageBox>
21#include <KDChartLegend>
22#include <KDChartLineDiagram>
23#include <KDChartCartesianAxis>
24
25#include "StatsPanel.hpp"
26
27StatsPanel::StatsPanel(KissCount* kiss, wxUI *parent, bool lowResolution) :
28 KissPanel(kiss, parent, lowResolution), _plot(0)
29{
30 QHBoxLayout *hbox = new QHBoxLayout();
31 QVBoxLayout *vbox = new QVBoxLayout();
32 _hbox2 = new QHBoxLayout();
33 _vbox2 = new QVBoxLayout();
34 _vbox3 = new QVBoxLayout();
35 int i, nbCategories;
36 User* user = _kiss->GetUser();
37 std::vector<Account>::iterator accountIt;
38 std::vector<Category>::iterator categoryIt;
39 std::map<int, std::vector<int> > operations;
40 std::map<int, std::vector<int> >::iterator it;
41 QListWidgetItem* item;
42
43 _icons[KissPanel::LOW_RES_ICON] = STATS_LOW_ICON;
44 _icons[KissPanel::HIGH_RES_ICON] = STATS_ICON;
45
46 setLayout(vbox);
47
48 _monthFrom = new QComboBox(parent);
49 for(i=0; i<12; i++)
50 _monthFrom->addItem(wxUI::months[i]);
51 _yearFrom = new QComboBox(parent);
52
53 _monthTo = new QComboBox(parent);
54 for(i=0; i<12; i++)
55 _monthTo->addItem(wxUI::months[i]);
56 _yearTo = new QComboBox(parent);
57
58 operations = _kiss->GetAllOperations();
59
60 for(i=0, it = operations.begin(); it != operations.end(); it++, i++)
61 {
62 _yearFrom->addItem(QString::number(it->first));
63 _yearTo->addItem(QString::number(it->first));
64 }
65
66 if (i) i--;
67
68 _yearFrom->setCurrentIndex(i);
69 _yearTo->setCurrentIndex(i);
70 _monthFrom->setCurrentIndex(0);
71 _monthTo->setCurrentIndex(11);
72
73 QLabel* label = new QLabel(_("From"));
74 hbox->addWidget(label);
75 hbox->addWidget(_monthFrom);
76 hbox->addWidget(_yearFrom);
77
78 label = new QLabel(_("To"));
79 hbox->addWidget(label);
80 hbox->addWidget(_monthTo);
81 hbox->addWidget(_yearTo);
82
83 connect(_yearFrom, SIGNAL(currentIndexChanged(int)), this, SLOT(OnRangeChange(int)));
84 connect(_monthFrom, SIGNAL(currentIndexChanged(int)), this, SLOT(OnRangeChange(int)));
85 connect(_yearTo, SIGNAL(currentIndexChanged(int)), this, SLOT(OnRangeChange(int)));
86 connect(_monthTo, SIGNAL(currentIndexChanged(int)), this, SLOT(OnRangeChange(int)));
87
88 _account = new QListWidget(this);
89 for(i=0, accountIt = user->_accounts.begin(); accountIt != user->_accounts.end(); accountIt++, i++)
90 {
91item = new QListWidgetItem(accountIt->name, _account);
92if (accountIt->hidden)
93 item->setCheckState (Qt::Unchecked);
94else
95 item->setCheckState (Qt::Checked);
96 }
97
98 _account->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
99
100 connect(_account, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(OnAccountChange(QListWidgetItem*)));
101
102 _categories = new QString[user->GetCategoriesNumber()] ;
103 for(i=0, categoryIt = user->_categories.begin();
104 categoryIt != user->_categories.end();
105 categoryIt++, i++)
106 {
107 _categoriesIndexes[categoryIt->id] = i;
108 _categories[i] = _(categoryIt->name.toStdString().c_str()) ;
109 }
110
111 DEFAULT_FONT(font);
112
113 _costRepartitionBanner = new CostRepartitionBanner(_kiss, this, _categories);
114
115 _vbox3->addWidget(_account);
116
117 nbCategories = user->GetCategoriesNumber();
118
119 _categoriesValues = new int[nbCategories];
120 for(i=0; i<nbCategories; i++)
121 _categoriesValues[i] = 0.0;
122
123 _vbox3->addWidget(_costRepartitionBanner);
124
125 _vbox2->addLayout(hbox);
126 _hbox2->addLayout(_vbox2);
127 vbox->addLayout(_hbox2);
128
129 _hbox2->addLayout(_vbox3);
130
131 OnRangeChange(0);
132
133 layout();
134}
135
136KissPanel* StatsPanel::CreatePanel()
137{
138 return new StatsPanel(_kiss, _wxUI, _lowResolution);
139}
140
141QString StatsPanel::GetToolTip()
142{
143 return _("Statistics");
144}
145
146void StatsPanel::UpdateStats(int monthFrom, int yearFrom, int monthTo, int yearTo)
147{
148 std::map<int, std::map<int, std::map<int, int> > > accountAmounts;
149 std::map<int, int> categories;
150 std::map<int, std::vector<int> > operations;
151 std::vector<Account>::iterator accountIt;
152 std::map<int, int>::iterator categoriesIt;
153 std::map<int, std::map<int, int> >::iterator accountYearIt;
154 int total;
155 int account, size, i, a, b, nbDays;
156 QString value, v;
157 User* user = _kiss->GetUser();
158 QDate date;
159 bool failed;
160 QVector<double> vec;
161 QStringList xlabels;
162
163 if (_plot)
164 {
165_vbox2->removeWidget(_plot);
166 delete _plot;
167 }
168
169 _plot = new KDChart::Widget();
170
171 if (monthFrom == monthTo && yearFrom == yearTo)
172 {
173date.setDate(yearFrom, monthFrom+1, 1);
174 nbDays = date.daysInMonth();
175
176 _kiss->GetMonthStats(monthFrom, yearFrom, nbDays, &operations, &categories);
177
178 // Line on 0 all over the years
179 for (a=0; a<nbDays; a++)
180 vec << 0.0;
181
182_plot->setDataset(0, vec, "");
183
184i=0;
185 for (account = 0, i = 0, accountIt = user->_accounts.begin(); accountIt != user->_accounts.end();
186 account++, accountIt++)
187 {
188 if (_account->item(account)->checkState() != Qt::Checked)
189 continue;
190
191 vec.clear();
192 for (a=0; a<nbDays; a++)
193vec << (double) operations[accountIt->id][a] / 100;
194
195 _plot->setDataset(++i, vec, user->GetAccountName(accountIt->id));
196 }
197 }
198 else
199 {
200 _kiss->GetStats(monthFrom, yearFrom, monthTo, yearTo, &accountAmounts, &categories);
201
202 // Line on 0 all over the years
203nbDays = ((yearTo - yearFrom) + 1) * 12;
204for (a=0; a<(nbDays/12); a++)
205{
206 for(b=0; b<12; b++)
207 {
208vec << 0.0;
209if (b == 0 || b == 5 || (b == 11 /*&& a == ((nbDays/12)-1))*/))
210 xlabels << wxUI::months[b] + " " + QString::number(yearFrom+a);
211else
212 xlabels << "" ;
213 }
214}
215
216_plot->setDataset(0, vec, "");
217
218 for (account = 0, i = 0, accountIt = user->_accounts.begin(); accountIt != user->_accounts.end();
219 account++, accountIt++, i++)
220 {
221 if (_account->item(account)->checkState() != Qt::Checked)
222 {
223 i-- ;
224 continue;
225 }
226
227 vec.clear();
228 for(a = 0, accountYearIt = accountAmounts[accountIt->id].begin();
229 accountYearIt != accountAmounts[accountIt->id].end();
230 accountYearIt++, a++)
231 {
232 for(b = 0; b<=12; b++)
233 {
234 if (!accountAmounts[accountIt->id][accountYearIt->first].count(b))
235 {
236 /*
237 If previously failed, continue to avoid to set
238 account to 0 (only for display)
239 */
240 if (!b || failed) continue;
241 /*
242 Compute cur month value (if there are operations)
243 as next month value
244 */
245 vec << (double) (accountAmounts[accountIt->id][accountYearIt->first][b-1]
246+ _kiss->CalcAccountAmount(accountIt->id, b-1, accountYearIt->first, 0)) / 100;
247 failed = true;
248 }
249 else
250 {
251 vec << (double) accountAmounts[accountIt->id][accountYearIt->first][b] / 100;
252 failed = false;
253 }
254 size++;
255 }
256 }
257 _plot->setDataset(i+1, vec, user->GetAccountName(accountIt->id));
258 }
259 }
260
261 KDChart::CartesianAxis *xAxis = new KDChart::CartesianAxis(_plot->lineDiagram());
262 KDChart::CartesianAxis *yAxis = new KDChart::CartesianAxis (_plot->lineDiagram());
263 xAxis->setPosition (KDChart::CartesianAxis::Bottom);
264 yAxis->setPosition (KDChart::CartesianAxis::Left);
265 yAxis->setTitleText (_("Amount"));
266
267 xAxis->setLabels(xlabels);
268 xAxis->setShortLabels(xlabels);
269
270 // Rotate only for months names
271 if (monthFrom != monthTo || yearFrom != yearTo)
272 {
273KDChart::TextAttributes axisTextAttr(xAxis->textAttributes());
274axisTextAttr.setRotation(-60);
275xAxis->setTextAttributes(axisTextAttr);
276xAxis->setTitleText (_("Months"));
277 }
278 else
279xAxis->setTitleText (_("Days"));
280
281 _plot->lineDiagram()->addAxis(xAxis);
282 _plot->lineDiagram()->addAxis(yAxis);
283
284 _plot->addLegend(KDChart::Position::East);
285 KDChart::Legend* legend = _plot->legend();
286 legend->setOrientation(Qt::Vertical);
287 legend->setTitleText(_("Accounts"));
288 legend->setText(0, _("0 line"));
289 {
290i = 1;
291for (a=0, accountIt = user->_accounts.begin(); accountIt != user->_accounts.end();
292 a++, accountIt++)
293{
294 if (_account->item(a)->checkState() == Qt::Checked)
295legend->setText(i++, accountIt->name);
296}
297 }
298
299 _vbox2->addWidget(_plot);
300
301 total = 0.0;
302 for(i=0, categoriesIt = categories.begin(); categoriesIt != categories.end(); categoriesIt++, i++)
303 {
304 _categoriesValues[_categoriesIndexes[categoriesIt->first]] = categoriesIt->second;
305 total += categoriesIt->second;
306 }
307
308 _costRepartitionBanner->UpdateCosts(_categoriesValues, total);
309
310 layout();
311}
312
313void StatsPanel::OnShow()
314{
315 _wxUI->setWindowTitle(_kiss->GetUser()->_name + _(" - ") + _("Statistics"));
316}
317
318void StatsPanel::OnRangeChange(int index)
319{
320 int monthFrom, monthTo, yearFrom, yearTo;
321
322 monthFrom = _monthFrom->currentIndex();
323 yearFrom = _yearFrom->currentText().toInt();
324 monthTo = _monthTo->currentIndex();
325 yearTo = _yearTo->currentText().toInt();
326
327 if (yearTo < yearFrom ||
328 (yearFrom == yearTo && monthFrom > monthTo))
329 {
330 QMessageBox::critical(0, _("Error"), _("Invalide date range"));
331 return;
332 }
333
334 _costRepartitionBanner->Reset();
335 UpdateStats(monthFrom, yearFrom, monthTo, yearTo);
336}
337
338void StatsPanel::OnAccountChange(QListWidgetItem* item)
339{
340 OnRangeChange(0);
341}

Archive Download this file