/* Copyright 2010-2012 Grégory Soutadé This file is part of KissCount. KissCount is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. KissCount is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with KissCount. If not, see . */ #include #include #include #include #include #include "StatsPanel.hpp" StatsPanel::StatsPanel(KissCount* kiss, wxUI *parent) : KissPanel(kiss, parent), _plot(0) { QHBoxLayout *hbox = new QHBoxLayout(); QVBoxLayout *vbox = new QVBoxLayout(); _hbox2 = new QHBoxLayout(); _vbox2 = new QVBoxLayout(); _vbox3 = new QVBoxLayout(); int i; User* user = _kiss->GetUser(); std::vector::iterator accountIt; std::vector::iterator categoryIt; std::map > operations; std::map >::iterator it; int nbCategories; QListWidgetItem* item; setLayout(vbox); _monthFrom = new QComboBox(parent); for(i=0; i<12; i++) _monthFrom->addItem(wxUI::months[i]); _yearFrom = new QComboBox(parent); _monthTo = new QComboBox(parent); for(i=0; i<12; i++) _monthTo->addItem(wxUI::months[i]); _yearTo = new QComboBox(parent); operations = _kiss->GetAllOperations(); for(i=0, it = operations.begin(); it != operations.end(); it++, i++) { _yearFrom->addItem(QString::number(it->first)); _yearTo->addItem(QString::number(it->first)); } if (i) i--; _yearFrom->setCurrentIndex(i); _yearTo->setCurrentIndex(i); _monthFrom->setCurrentIndex(0); _monthTo->setCurrentIndex(11); QLabel* label = new QLabel(_("From")); hbox->addWidget(label); hbox->addWidget(_monthFrom); hbox->addWidget(_yearFrom); label = new QLabel(_("To")); hbox->addWidget(label); hbox->addWidget(_monthTo); hbox->addWidget(_yearTo); connect(_yearFrom, SIGNAL(currentIndexChanged(int)), this, SLOT(OnRangeChange(int))); connect(_monthFrom, SIGNAL(currentIndexChanged(int)), this, SLOT(OnRangeChange(int))); connect(_yearTo, SIGNAL(currentIndexChanged(int)), this, SLOT(OnRangeChange(int))); connect(_monthTo, SIGNAL(currentIndexChanged(int)), this, SLOT(OnRangeChange(int))); _account = new QListWidget(this); for(i=0, accountIt = user->_accounts.begin(); accountIt != user->_accounts.end(); accountIt++, i++) { item = new QListWidgetItem(accountIt->name, _account); item->setCheckState (Qt::Checked); } _account->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); connect(_account, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(OnAccountChange(QListWidgetItem*))); _categories = new QString[user->GetCategoriesNumber()] ; for(i=0, categoryIt = user->_categories.begin(); categoryIt != user->_categories.end(); categoryIt++, i++) { _categoriesIndexes[categoryIt->id] = i; _categories[i] = _(categoryIt->name.toStdString().c_str()) ; } DEFAULT_FONT(font); _statsGrid = new QTableWidget(this); _statsGrid->setRowCount(user->GetCategoriesNumber()+1); _statsGrid->setColumnCount(2); _statsGrid->verticalHeader()->setHidden(true); _statsGrid->horizontalHeader()->setHidden(true); _statsGrid->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); for(i=0; iGetCategoriesNumber(); i++) { if (i) { _statsGrid->setItem(i+1, 0, new QTableWidgetItem(_categories[i])); _statsGrid->item(i+1, 0)->setTextAlignment(Qt::AlignLeft|Qt::AlignVCenter); } else { _statsGrid->setItem(i, 0, new QTableWidgetItem(_categories[i])); _statsGrid->item(i, 0)->setTextAlignment(Qt::AlignLeft|Qt::AlignVCenter); } } _statsGrid->setItem(1, 0, new QTableWidgetItem(_("Non fix"))); _statsGrid->setItem(1, 1, new QTableWidgetItem("")); _statsGrid->item(1, 1)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); _vbox3->addWidget(_account); _vbox3->addWidget(_statsGrid); nbCategories = (user->GetCategoriesNumber() <= wxUI::MAX_CATEGORY) ? user->GetCategoriesNumber() : wxUI::MAX_CATEGORY; _categoriesValues = new double[user->GetCategoriesNumber()]; for(i=0; iGetCategoriesNumber(); i++) _categoriesValues[i] = 0.0; _pie = new KDChart::Widget(); _pie->setType( KDChart::Widget::Pie); QPen pen; pen.setWidth(2); pen.setColor(Qt::black); _pie->pieDiagram()->setPen(pen); _pie->addLegend(KDChart::Position::South); KDChart::Legend* legend = _pie->legend(); legend->setOrientation(Qt::Vertical); legend->setTitleText(_("Cost repartition")); QVector< double > vec; vec << 0.0; _categoriesValues = new double[nbCategories]; for(i=0; isetDataset(i, vec, _categories[i]); _pie->pieDiagram()->setBrush(i, QBrush(wxUI::categoryColors[i])); legend->setText(i, _categories[i]); } _pie->setMinimumSize(200, 400); _pie->setMaximumSize(200, 400); KDChart::TextAttributes legendTextAttr(legend->textAttributes()); legendTextAttr.setFontSize(64); legendTextAttr.setAutoShrink(true); legend->setTextAttributes(legendTextAttr); legendTextAttr = KDChart::TextAttributes(legend->titleTextAttributes()); legendTextAttr.setFontSize(64); legendTextAttr.setAutoShrink(true); legend->setTitleTextAttributes(legendTextAttr); _vbox2->addLayout(hbox); _hbox2->addLayout(_vbox2); vbox->addLayout(_hbox2); OnRangeChange(0); layout(); } KissPanel* StatsPanel::CreatePanel() { return new StatsPanel(_kiss, _wxUI); } QPushButton* StatsPanel::GetButton() { if (!_KissButton) { _KissButton = new QPushButton(QIcon(STATS_ICON), "", this); _KissButton->setFixedSize(128, 128); _KissButton->setIconSize(QSize(128, 128)); } return _KissButton; } QString StatsPanel::GetToolTip() { return _("Statistics"); } void StatsPanel::UpdateStats(int monthFrom, int yearFrom, int monthTo, int yearTo) { std::map > > accountAmounts; std::map categories; std::map > operations; std::vector::iterator accountIt; std::map::iterator categoriesIt; std::map >::iterator accountYearIt; double total, non_fix; int account, size, i, a, b, percents, nbDays; QString value; User* user = _kiss->GetUser(); QDate date; bool failed; QVector vec; QStringList xlabels; if (_plot) { _vbox2->removeWidget(_plot); _hbox2->removeItem(_vbox3); _hbox2->removeWidget(_pie); delete _plot; } _plot = new KDChart::Widget(); if (monthFrom == monthTo && yearFrom == yearTo) { date.setDate(yearFrom, monthFrom+1, 1); nbDays = date.daysInMonth(); _kiss->GetMonthStats(monthFrom, yearFrom, nbDays, &operations, &categories); // Line on 0 all over the years for (a=0; asetDataset(0, vec, ""); vec.clear(); for (account = 0, i = 0, accountIt = user->_accounts.begin(); accountIt != user->_accounts.end(); account++, accountIt++, i++) { if (_account->item(account)->checkState() != Qt::Checked) { i-- ; continue; } for (a=0; aid][a]; _plot->setDataset(i+1, vec, user->GetAccountName(accountIt->id)); } } else { _kiss->GetStats(monthFrom, yearFrom, monthTo, yearTo, &accountAmounts, &categories); // Line on 0 all over the years nbDays = ((yearTo - yearFrom) + 1) * 12; for (a=0; a<(nbDays/12); a++) { for(b=0; b<12; b++) { vec << 0.0; if (b == 0 || b == 5 || (b == 11 /*&& a == ((nbDays/12)-1))*/)) xlabels << wxUI::months[b] + " " + QString::number(yearFrom+a); else xlabels << "" ; } } _plot->setDataset(0, vec, ""); for (account = 0, i = 0, accountIt = user->_accounts.begin(); accountIt != user->_accounts.end(); account++, accountIt++, i++) { if (_account->item(account)->checkState() != Qt::Checked) { i-- ; continue; } vec.clear(); for(a = 0, accountYearIt = accountAmounts[accountIt->id].begin(); accountYearIt != accountAmounts[accountIt->id].end(); accountYearIt++, a++) { for(b = 0; b<=12; b++) { if (!accountAmounts[accountIt->id][accountYearIt->first].count(b)) { /* If previously failed, continue to avoid to set account to 0 (only for display) */ if (!b || failed) continue; /* Compute cur month value (if there are operations) as next month value */ vec << accountAmounts[accountIt->id][accountYearIt->first][b-1] + _kiss->CalcAccountAmount(accountIt->id, b-1, accountYearIt->first, 0); failed = true; } else { vec << accountAmounts[accountIt->id][accountYearIt->first][b]; failed = false; } size++; } } _plot->setDataset(i+1, vec, user->GetAccountName(accountIt->id)); } } KDChart::CartesianAxis *xAxis = new KDChart::CartesianAxis(_plot->lineDiagram()); KDChart::CartesianAxis *yAxis = new KDChart::CartesianAxis (_plot->lineDiagram()); xAxis->setPosition (KDChart::CartesianAxis::Bottom); yAxis->setPosition (KDChart::CartesianAxis::Left); xAxis->setTitleText (_("Months")); yAxis->setTitleText (_("Amount")); xAxis->setLabels(xlabels); xAxis->setShortLabels(xlabels); KDChart::TextAttributes axisTextAttr(xAxis->textAttributes()); axisTextAttr.setRotation(-60); xAxis->setTextAttributes(axisTextAttr); _plot->lineDiagram()->addAxis(xAxis); _plot->lineDiagram()->addAxis(yAxis); _plot->addLegend(KDChart::Position::East); KDChart::Legend* legend = _plot->legend(); legend->setOrientation(Qt::Vertical); legend->setTitleText(_("Accounts")); legend->setText(0, _("0 line")); { QVector vec; i = 1; for (a=0, accountIt = user->_accounts.begin(); accountIt != user->_accounts.end(); a++, accountIt++) { if (_account->item(a)->checkState() == Qt::Checked) legend->setText(i++, accountIt->name); } } _vbox2->addWidget(_plot); total = 0.0; for(categoriesIt = categories.begin(); categoriesIt != categories.end(); categoriesIt++) total += categoriesIt->second; for(i=0, categoriesIt = categories.begin(); categoriesIt != categories.end(); categoriesIt++, i++) { _categoriesValues[_categoriesIndexes[categoriesIt->first]] = categoriesIt->second; if (total) percents = ((double) (categoriesIt->second*100))/total; else percents = 0; value = value.sprintf("%0.2lf (%02d%%)", categoriesIt->second, percents); if (i) { _statsGrid->setItem(_categoriesIndexes[categoriesIt->first]+1, 1, new QTableWidgetItem(value)); _statsGrid->item(_categoriesIndexes[categoriesIt->first]+1, 1)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); } else { _statsGrid->setItem(_categoriesIndexes[categoriesIt->first], 1, new QTableWidgetItem(value)); _statsGrid->item(_categoriesIndexes[categoriesIt->first], 1)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter); } QVector< double > vec; vec << _categoriesValues[_categoriesIndexes[categoriesIt->first]]; _pie->setDataset(_categoriesIndexes[categoriesIt->first], vec, _categories[_categoriesIndexes[categoriesIt->first]]); } non_fix = total - _categoriesValues[0]; if (total) percents = ((double) (non_fix*100))/total; else percents = 0; value = value.sprintf("%0.2lf (%02d%%)", non_fix, percents); _statsGrid->setItem(1, 1, new QTableWidgetItem(value)); _statsGrid->resizeColumnsToContents(); _hbox2->addLayout(_vbox3); _hbox2->addWidget(_pie); layout(); } void StatsPanel::OnShow() { _wxUI->setWindowTitle(_kiss->GetUser()->_name + _(" - ") + _("Statistics")); } void StatsPanel::OnRangeChange(int index) { int monthFrom, monthTo, yearFrom, yearTo; monthFrom = _monthFrom->currentIndex(); yearFrom = _yearFrom->currentText().toInt(); monthTo = _monthTo->currentIndex(); yearTo = _yearTo->currentText().toInt(); if (yearTo < yearFrom || (yearFrom == yearTo && monthFrom > monthTo)) { QMessageBox::critical(0, _("Error"), _("Invalide date range")); return; } UpdateStats(monthFrom, yearFrom, monthTo, yearTo); } void StatsPanel::OnAccountChange(QListWidgetItem* item) { OnRangeChange(0); }