KissCount/src/view/StatsPanel.cpp

442 lines
13 KiB
C++
Raw Normal View History

2012-02-05 15:54:09 +01:00
/*
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 <http://www.gnu.org/licenses/>.
*/
#include <QMessageBox>
#include <KDChartLegend>
#include <KDChartPieDiagram>
2012-02-11 10:47:09 +01:00
#include <KDChartLineDiagram>
#include <KDChartCartesianAxis>
2012-02-05 15:54:09 +01:00
#include "StatsPanel.hpp"
2012-02-11 10:47:09 +01:00
StatsPanel::StatsPanel(KissCount* kiss, wxUI *parent) : KissPanel(kiss, parent), _plot(0)
2012-02-05 15:54:09 +01:00
{
QHBoxLayout *hbox = new QHBoxLayout();
QVBoxLayout *vbox = new QVBoxLayout();
_hbox2 = new QHBoxLayout();
_vbox2 = new QVBoxLayout();
2012-02-11 11:40:09 +01:00
_vbox3 = new QVBoxLayout();
2012-02-05 15:54:09 +01:00
int i;
User* user = _kiss->GetUser();
std::vector<Account>::iterator accountIt;
std::vector<Category>::iterator categoryIt;
std::map<int, std::vector<int> > operations;
std::map<int, std::vector<int> >::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);
if (accountIt->hidden)
item->setCheckState (Qt::Unchecked);
else
item->setCheckState (Qt::Checked);
2012-02-05 15:54:09 +01:00
}
2012-02-11 10:47:09 +01:00
_account->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
2012-02-05 15:54:09 +01:00
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; i<user->GetCategoriesNumber(); 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);
2012-02-11 11:40:09 +01:00
_vbox3->addWidget(_account);
_vbox3->addWidget(_statsGrid);
2012-02-05 15:54:09 +01:00
nbCategories = user->GetCategoriesNumber();
// nbCategories = (user->GetCategoriesNumber() <= wxUI::MAX_CATEGORY) ? user->GetCategoriesNumber() : wxUI::MAX_CATEGORY;
2012-02-05 15:54:09 +01:00
_categoriesValues = new double[user->GetCategoriesNumber()];
for(i=0; i<user->GetCategoriesNumber(); i++)
_categoriesValues[i] = 0.0;
_pie = new KDChart::Widget();
2012-02-11 10:47:09 +01:00
_pie->setType( KDChart::Widget::Pie);
2012-02-05 15:54:09 +01:00
QPen pen;
pen.setWidth(2);
pen.setColor(Qt::black);
_pie->pieDiagram()->setPen(pen);
_pie->addLegend(KDChart::Position::South);
KDChart::Legend* legend = _pie->legend();
2012-02-11 10:47:09 +01:00
legend->setOrientation(Qt::Vertical);
legend->setTitleText(_("Cost repartition"));
2012-02-05 15:54:09 +01:00
QVector< double > vec;
vec << 0.0;
_categoriesValues = new double[nbCategories];
for(i=0; i<nbCategories; i++)
{
_categoriesValues[i] = 0.0;
2012-02-11 10:47:09 +01:00
_pie->setDataset(i, vec, _categories[i]);
if (i < wxUI::MAX_CATEGORY)
_pie->pieDiagram()->setBrush(i, QBrush(wxUI::categoryColors[i]));
2012-02-11 10:47:09 +01:00
legend->setText(i, _categories[i]);
2012-02-05 15:54:09 +01:00
}
2012-02-11 10:47:09 +01:00
_pie->setMinimumSize(200, 400);
_pie->setMaximumSize(200, 400);
2012-02-05 15:54:09 +01:00
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);
2012-02-11 11:40:09 +01:00
_vbox2->addLayout(hbox);
_hbox2->addLayout(_vbox2);
2012-02-05 15:54:09 +01:00
vbox->addLayout(_hbox2);
_hbox2->addLayout(_vbox3);
_hbox2->addWidget(_pie);
2012-02-05 15:54:09 +01:00
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<int, std::map<int, std::map<int, double> > > accountAmounts;
std::map<int, double> categories;
std::map<int, std::vector<double> > operations;
std::vector<Account>::iterator accountIt;
std::map<int, double>::iterator categoriesIt;
std::map<int, std::map<int, double> >::iterator accountYearIt;
double total, non_fix;
int account, size, i, a, b, percents, nbDays;
QString value, v;
2012-02-05 15:54:09 +01:00
User* user = _kiss->GetUser();
QDate date;
bool failed;
2012-02-11 10:47:09 +01:00
QVector<double> vec;
QStringList xlabels;
2012-02-05 15:54:09 +01:00
2012-02-11 10:47:09 +01:00
if (_plot)
2012-02-05 15:54:09 +01:00
{
2012-02-11 11:40:09 +01:00
_vbox2->removeWidget(_plot);
2012-02-11 10:47:09 +01:00
delete _plot;
2012-02-05 15:54:09 +01:00
}
2012-02-11 10:47:09 +01:00
_plot = new KDChart::Widget();
2012-02-05 15:54:09 +01:00
if (monthFrom == monthTo && yearFrom == yearTo)
{
date.setDate(yearFrom, monthFrom+1, 1);
nbDays = date.daysInMonth();
_kiss->GetMonthStats(monthFrom, yearFrom, nbDays, &operations, &categories);
2012-02-11 10:47:09 +01:00
// Line on 0 all over the years
for (a=0; a<nbDays; a++)
vec << 0.0;
_plot->setDataset(0, vec, "");
2012-03-11 17:54:42 +01:00
i=0;
2012-02-11 10:47:09 +01:00
for (account = 0, i = 0, accountIt = user->_accounts.begin(); accountIt != user->_accounts.end();
account++, accountIt++)
2012-02-11 10:47:09 +01:00
{
if (_account->item(account)->checkState() != Qt::Checked)
continue;
2012-03-11 17:54:42 +01:00
vec.clear();
for (a=0; a<nbDays; a++)
2012-02-11 10:47:09 +01:00
vec << operations[accountIt->id][a];
2012-03-11 17:54:42 +01:00
_plot->setDataset(++i, vec, user->GetAccountName(accountIt->id));
2012-02-11 10:47:09 +01:00
}
2012-02-05 15:54:09 +01:00
}
else
{
_kiss->GetStats(monthFrom, yearFrom, monthTo, yearTo, &accountAmounts, &categories);
2012-02-11 10:47:09 +01:00
// 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;
2012-02-11 11:40:09 +01:00
if (b == 0 || b == 5 || (b == 11 /*&& a == ((nbDays/12)-1))*/))
2012-02-11 10:47:09 +01:00
xlabels << wxUI::months[b] + " " + QString::number(yearFrom+a);
else
xlabels << "" ;
}
}
_plot->setDataset(0, vec, "");
2012-02-05 15:54:09 +01:00
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;
}
2012-02-11 10:47:09 +01:00
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));
2012-02-05 15:54:09 +01:00
}
}
2012-02-11 10:47:09 +01:00
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);
yAxis->setTitleText (_("Amount"));
xAxis->setLabels(xlabels);
2012-02-11 11:40:09 +01:00
xAxis->setShortLabels(xlabels);
// Rotate only for months names
if (monthFrom != monthTo || yearFrom != yearTo)
{
KDChart::TextAttributes axisTextAttr(xAxis->textAttributes());
axisTextAttr.setRotation(-60);
xAxis->setTextAttributes(axisTextAttr);
xAxis->setTitleText (_("Months"));
}
else
xAxis->setTitleText (_("Days"));
2012-02-11 11:40:09 +01:00
2012-02-11 10:47:09 +01:00
_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"));
{
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);
}
}
2012-02-05 15:54:09 +01:00
2012-02-11 11:40:09 +01:00
_vbox2->addWidget(_plot);
2012-02-05 15:54:09 +01:00
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 = v.sprintf("%0.2lf (%02d%%)", categoriesIt->second, percents);
2012-02-05 15:54:09 +01:00
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;
2012-02-11 10:47:09 +01:00
vec << _categoriesValues[_categoriesIndexes[categoriesIt->first]];
_pie->setDataset(_categoriesIndexes[categoriesIt->first], vec, _categories[_categoriesIndexes[categoriesIt->first]]);
2012-02-05 15:54:09 +01:00
}
non_fix = total - _categoriesValues[0];
if (total)
percents = ((double) (non_fix*100))/total;
else
percents = 0;
value = v.sprintf("%0.2lf (%02d%%)", non_fix, percents);
2012-02-05 15:54:09 +01:00
_statsGrid->setItem(1, 1, new QTableWidgetItem(value));
_statsGrid->resizeColumnsToContents();
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);
}