From c05fbb95f6a2ee1e18a69d62d0e3dab4c248a310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Soutad=C3=A9?= Date: Sun, 5 Feb 2012 15:54:09 +0100 Subject: [PATCH] Work on StatsPanel --- src/view/AccountPanel.cpp | 12 +- src/view/StatsPanel.cpp | 447 ++++++++++++++++++++++++++++++++++++++ src/view/StatsPanel.hpp | 62 ++++++ src/view/wxUI.cpp | 9 +- 4 files changed, 519 insertions(+), 11 deletions(-) create mode 100644 src/view/StatsPanel.cpp create mode 100644 src/view/StatsPanel.hpp diff --git a/src/view/AccountPanel.cpp b/src/view/AccountPanel.cpp index 1a52d12..b0748c2 100644 --- a/src/view/AccountPanel.cpp +++ b/src/view/AccountPanel.cpp @@ -270,12 +270,12 @@ void AccountPanel::InitStatsGrid(User* user) _statsGrid->setItem(BALANCE, 0, new QTableWidgetItem(_("Balance"))); _statsGrid->setItem(NON_FIX, 0, new QTableWidgetItem(_("Non fix"))); - _statsGrid->setItem(CUR_CREDIT, 1, new QTableWidgetItem(_(""))); - _statsGrid->setItem(CUR_DEBIT, 1, new QTableWidgetItem(_(""))); - _statsGrid->setItem(TOTAL_CREDIT, 1, new QTableWidgetItem(_(""))); - _statsGrid->setItem(TOTAL_DEBIT, 1, new QTableWidgetItem(_(""))); - _statsGrid->setItem(BALANCE, 1, new QTableWidgetItem(_(""))); - _statsGrid->setItem(NON_FIX, 1, new QTableWidgetItem(_(""))); + _statsGrid->setItem(CUR_CREDIT, 1, new QTableWidgetItem("")); + _statsGrid->setItem(CUR_DEBIT, 1, new QTableWidgetItem("")); + _statsGrid->setItem(TOTAL_CREDIT, 1, new QTableWidgetItem("")); + _statsGrid->setItem(TOTAL_DEBIT, 1, new QTableWidgetItem("")); + _statsGrid->setItem(BALANCE, 1, new QTableWidgetItem("")); + _statsGrid->setItem(NON_FIX, 1, new QTableWidgetItem("")); _statsGrid->item(CUR_DEBIT, 0)->setFont(font); _statsGrid->item(CUR_CREDIT, 0)->setFont(font); diff --git a/src/view/StatsPanel.cpp b/src/view/StatsPanel.cpp new file mode 100644 index 0000000..e92e7aa --- /dev/null +++ b/src/view/StatsPanel.cpp @@ -0,0 +1,447 @@ +/* + 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 "StatsPanel.hpp" + +StatsPanel::StatsPanel(KissCount* kiss, wxUI *parent) : KissPanel(kiss, parent) //, _plot(0), _chart(0) +{ + QHBoxLayout *hbox = new QHBoxLayout(); + QVBoxLayout *vbox = new QVBoxLayout(); + _hbox2 = new QHBoxLayout(); + _vbox2 = 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); + } + + 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); + + _vbox2->addWidget(_account); + _vbox2->addWidget(_statsGrid); + + nbCategories = (user->GetCategoriesNumber() <= wxUI::MAX_CATEGORY) ? user->GetCategoriesNumber() : wxUI::MAX_CATEGORY; + + // _dataset = new CategorySimpleDataset(_categories, nbCategories); + // ColorScheme* colorScheme = new ColorScheme(wxUI::categoryColors, WXSIZEOF(wxUI::categoryColors)); + + _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->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); + + vbox->addLayout(hbox); + 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; + double *amounts; + QString value; + User* user = _kiss->GetUser(); + QDate date; + bool failed; + + // if (_chart) + { + // _hbox2->removeWidget(_chart); + _hbox2->removeItem(_vbox2); + // _hbox2->removeWidget(_chartCategories); + // delete _chart; + } + + // first step: create plot + // _plot = new XYPlot(); + + // create dataset + // XYSimpleDataset *dataset = new XYSimpleDataset(); + + 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 + // amounts = new double[nbDays*2]; + // for (a=0; aAddSerie((double *) amounts, nbDays); + // delete[] amounts; + + // for (account = 0, i = 0, accountIt = user->_accounts.begin(); accountIt != user->_accounts.end(); + // account++, accountIt++, i++) + // { + // if (!_account->IsChecked(account)) + // { + // i-- ; + // continue; + // } + + // amounts = new double[nbDays*2]; + // size = 0; + // for (a=0; aid][a]; + // } + // dataset->AddSerie((double *) amounts, nbDays); + // // set serie names to be displayed on legend + // dataset->SetSerieName(i+1, user->GetAccountName(accountIt->id)); + // delete[] amounts; + // } + } + else + { + _kiss->GetStats(monthFrom, yearFrom, monthTo, yearTo, &accountAmounts, &categories); + + // // Line on 0 all over the years + // size = ((yearTo - yearFrom) + 1) * 12; + // amounts = new double[size*2]; + // for (a=0; a<(size/12); a++) + // { + // for(b=0; b<12; b++) + // { + // amounts[a*12*2+b*2+0] = a*12+b; + // amounts[a*12*2+b*2+1] = 0; + // } + // } + + // dataset->AddSerie((double *) amounts, size); + // delete[] amounts; + + 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; + } + + // size = accountAmounts[accountIt->id].size(); + // amounts = new double[size*13*2]; + // size = 0; + // for(a = 0, accountYearIt = accountAmounts[accountIt->id].begin(); + // accountYearIt != accountAmounts[accountIt->id].end(); + // accountYearIt++, a++) + // { + // for(b = 0; b<=12; b++) + // { + // amounts[size*2+0] = a*12+b; + // if (!accountAmounts[accountIt->id][accountYearIt->first].count(b)) + // { + // /* + // If previously afiled, 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 + // */ + // amounts[size*2+1] = + // accountAmounts[accountIt->id][accountYearIt->first][b-1] + // + _kiss->CalcAccountAmount(accountIt->id, b-1, accountYearIt->first, 0); + // failed = true; + // } + // else + // { + // amounts[size*2+1] = accountAmounts[accountIt->id][accountYearIt->first][b]; + // failed = false; + // } + // size++; + // } + // } + // dataset->AddSerie((double *) amounts, size); + // // set serie names to be displayed on legend + // dataset->SetSerieName(i+1, user->GetAccountName(accountIt->id)); + // delete[] amounts; + } + } + + // // create line renderer and set it to dataset + // XYLineRenderer *renderer = new XYLineRenderer(true, true); + // dataset->SetRenderer(renderer); + + // // add our dataset to plot + // _plot->AddDataset(dataset); + + // // create left and bottom number axes + // NumberAxis *leftAxis = new NumberAxis(AXIS_LEFT); + // NumberAxis *bottomAxis = new NumberAxis(AXIS_BOTTOM); + + // // add axes to plot + // _plot->AddAxis(leftAxis); + // _plot->AddAxis(bottomAxis); + + // // link axes and dataset + // _plot->LinkDataVerticalAxis(0, 0); + // _plot->LinkDataHorizontalAxis(0, 0); + + // // set legend + // _plot->SetLegend(new Legend(wxCENTER, wxRIGHT)); + + // _chart = new wxChartPanel(this); + // _chart->SetChart(new Chart(_plot, _("Accounts"))); + // _chart->Fit(); + // _chart->Layout(); + // _chart->SetMinSize(// chart->GetSize() + // wxSize(750,550)); + + // _hbox2->Add(_chart, 0, wxGROW|wxALL, 5); + + 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[i]; + _pie->setDataset( i, vec, _categories[i] ); + } + + 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(_vbox2); + _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); +} diff --git a/src/view/StatsPanel.hpp b/src/view/StatsPanel.hpp new file mode 100644 index 0000000..fe1a971 --- /dev/null +++ b/src/view/StatsPanel.hpp @@ -0,0 +1,62 @@ +/* + Copyright 2010-2011 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 . +*/ + +#ifndef STATSPANEL_H +#define STATSPANEL_H + +#include +#include + +#include "view.hpp" +#include + +class StatsPanel: public KissPanel +{ + Q_OBJECT; + +public: + StatsPanel(KissCount* kiss, wxUI *parent); + + KissPanel* CreatePanel(); + QPushButton* GetButton(); + QString GetToolTip(); + void OnShow(); + +private slots: + void OnRangeChange(int); + void OnAccountChange(QListWidgetItem*); + +private: + QCalendarWidget* _calendarFrom, *_calendarTo; + QComboBox* _monthFrom, *_yearFrom, *_monthTo, *_yearTo; + QTableWidget *_statsGrid; + KDChart::Widget* _pie; + double *_categoriesValues; + //CategorySimpleDataset* _dataset; + KDChart::Widget *_plot ; + QString* _categories; + std::map _categoriesIndexes; + QBoxLayout *_hbox2, *_vbox2; + //wxChartPanel* _chart, *_chartCategories; + QListWidget* _account; + + void UpdateStats(int monthFrom, int yearFrom, int monthTo, int yearTo); +}; + +#endif diff --git a/src/view/wxUI.cpp b/src/view/wxUI.cpp index c52b6f1..ac804f5 100644 --- a/src/view/wxUI.cpp +++ b/src/view/wxUI.cpp @@ -22,12 +22,11 @@ #include "AccountPanel.hpp" #include "SearchPanel.hpp" #include "PreferencesPanel.hpp" -/*#include "UsersDialog.hpp" +//#include "UsersDialog.hpp" #include "StatsPanel.hpp" -#include "ImportPanel.hpp" -#include "ExportPanel.hpp" +//#include "ImportPanel.hpp" +//#include "ExportPanel.hpp" -*/ #include "wxUI.hpp" #include "view.hpp" @@ -164,7 +163,7 @@ void wxUI::InitPanels() int id=0; ADD_PANEL(AccountPanel); - // ADD_PANEL(StatsPanel, 1); + ADD_PANEL(StatsPanel); ADD_PANEL(SearchPanel); ADD_PANEL(PreferencesPanel); // ADD_PANEL(ImportPanel, 4);