KissCount/src/view/AccountPanel.cpp

1202 lines
34 KiB
C++

/*
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 <QHeaderView>
#include <QGroupBox>
#include <QMessageBox>
#include <KDChartLegend>
#include <KDChartPieDiagram>
#include "AccountPanel.hpp"
#include "grid/FloatDelegate.hpp"
#include "GenerateDialog.hpp"
enum {ACCOUNT_NUMBER, ACCOUNT_NAME, ACCOUNT_INIT, ACCOUNT_CUR, ACCOUNT_FINAL, NUMBER_COLS_ACCOUNTS};
enum {CUR_CREDIT, CUR_DEBIT, TOTAL_CREDIT, TOTAL_DEBIT, BALANCE, STATS_ROW, CATS_STATS, NON_FIX};
enum {VIRTUAL_MODE=0, REAL_MODE, CHECK_MODE};
AccountPanel::AccountPanel(KissCount* kiss, wxUI *parent) : KissPanel(kiss, parent), _curMonth(-1), _curYear(-1), _inModification(false)
{
QHBoxLayout *hbox = new QHBoxLayout;
QHBoxLayout *hbox2 = new QHBoxLayout;
QVBoxLayout *vbox = new QVBoxLayout;
QVBoxLayout *vbox2 = new QVBoxLayout;
QVBoxLayout *vbox3 = new QVBoxLayout;
// wxChartPanel* chart ;
int i ;
User* user = _kiss->GetUser();
std::vector<Account>::iterator accountIt;
std::vector<Category>::iterator categoryIt;
int nbCategories;
setLayout(hbox);
_tree = new QTreeWidget(this);
_tree->headerItem()->setHidden(true);
_tree->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
connect(_tree, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(OnTreeChange(QTreeWidgetItem*, int)));
_tree->setContextMenuPolicy(Qt::CustomContextMenu);
connect(_tree, SIGNAL(customContextMenuRequested ( const QPoint & )), this, SLOT(OnTreeRightClick(const QPoint &)));
// ColorScheme* colorScheme = new ColorScheme(wxUI::categoryColors, WXSIZEOF(wxUI::categoryColors));
_calendar = new QCalendarWidget(this);
_calendar->setGridVisible(false);
_calendar->setFirstDayOfWeek(Qt::Monday);
_calendar->setNavigationBarVisible(false);
_calendar->setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader);
_calendar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
connect(_calendar, SIGNAL(selectionChanged ()), this, SLOT(OnCalendarChange()));
_accounts = new QString[user->GetAccountsNumber()];
for (i=0,
accountIt = user->_accounts.begin();
accountIt != user->_accounts.end();
accountIt++, i++)
_accounts[i] = accountIt->name;
_categories = new QString[user->GetCategoriesNumber()] ;
for(i=0, categoryIt = user->_categories.begin();
categoryIt != user->_categories.end();
categoryIt++, i++)
{
_categories[i] = _(categoryIt->name.toStdString().c_str()) ;
_categoriesIndexes[categoryIt->name] = i;
}
nbCategories = (user->GetCategoriesNumber() <= wxUI::MAX_CATEGORY) ? user->GetCategoriesNumber() : wxUI::MAX_CATEGORY;
_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->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
legend->setOrientation( Qt::Vertical );
legend->setTitleText( _("Cost repartition") );
QVector< double > vec;
vec << 0.0;
_dataset = new QStandardItemModel(nbCategories, 2, this);
_categoriesValues = new double[nbCategories];
for(i=0; i<nbCategories; i++)
{
_categoriesValues[i] = 0.0;
_pie->setDataset( i, vec, _categories[i] );
_pie->pieDiagram()->setBrush(i, QBrush(wxUI::categoryColors[i]));
legend->setText( i, _categories[i] );
_dataset->setData(_dataset->index(i, 0, QModelIndex()), _categories[i]);
_dataset->setData(_dataset->index(i, 1, QModelIndex()), 0.0);
_dataset->setData(_dataset->index(i, 0, QModelIndex()), wxUI::categoryColors[i], Qt::DecorationRole);
}
_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);
_grid = new GridAccount(_kiss, this, true, true, true);
_grid->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
_accountsGrid = new QTableWidget(this);
_accountsGrid->setColumnCount(NUMBER_COLS_ACCOUNTS);
_accountsGrid->setRowCount(0);
_accountsGrid->verticalHeader()->setHidden(true);
_accountsGrid->resizeColumnsToContents();
_accountsGrid->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(_accountsGrid, SIGNAL(cellChanged(int, int)), this, SLOT(OnAccountModified(int, int)));
_statsGrid = new QTableWidget(this);
_statsGrid->verticalHeader()->setHidden(true);
_statsGrid->horizontalHeader()->setHidden(true);
_statsGrid->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
QGroupBox *groupBox = new QGroupBox(_("Mode"));
_virtual = new QRadioButton(_("Virtual"));
_real = new QRadioButton(_("Real"));
_check = new QRadioButton(_("Check"));
_virtual->setChecked(true);
{
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(_virtual);
vbox->addWidget(_real);
vbox->addWidget(_check);
groupBox->setLayout(vbox);
}
connect(_virtual, SIGNAL(clicked()), this, SLOT(OnModeChange()));
connect(_real, SIGNAL(clicked()), this, SLOT(OnModeChange()));
connect(_check, SIGNAL(clicked()), this, SLOT(OnModeChange()));
// _tree.SetIndent(5);
QPushButton* buttonGroup = new QPushButton(_("Group"));
QPushButton* buttonUnGroup = new QPushButton(_("UnGroup"));
QPushButton* buttonUpdateNextMonths = new QPushButton(_("Update next months"));
connect(buttonGroup, SIGNAL(clicked()), this, SLOT(OnGroup()));
connect(buttonUnGroup, SIGNAL(clicked()), this, SLOT(OnUnGroup()));
connect(buttonUpdateNextMonths, SIGNAL(clicked()), this, SLOT(OnUpdateNextMonths()));
vbox3->addWidget(_tree);
vbox3->addWidget(buttonUpdateNextMonths);
vbox3->addStretch(1);
vbox3->addWidget(buttonGroup);
vbox3->addWidget(buttonUnGroup);
vbox3->addStretch(1);
vbox3->addWidget(groupBox);
hbox->addLayout(vbox3);
hbox2->addWidget(_accountsGrid, 2);
hbox2->addWidget(_calendar);
vbox2->addLayout(hbox2);
vbox2->addWidget(_grid, 1);
hbox->addLayout(vbox2);
vbox->addWidget(_statsGrid);
vbox->addWidget(_pie);
hbox->addLayout(vbox);
ChangeUser();
layout();
QSize s = legend->sizeHint();
legend->setMaximumSize(s.width(), s.height()/3);
}
AccountPanel::~AccountPanel()
{
delete[] _categoriesValues;
delete[] _categories;
delete[] _accounts;
}
KissPanel* AccountPanel::CreatePanel()
{
return new AccountPanel(_kiss, _wxUI);
}
QPushButton* AccountPanel::GetButton()
{
if (!_KissButton)
{
_KissButton = new QPushButton(QIcon(ACCOUNT_ICON), "", this);
_KissButton->setFixedSize(128, 128);
_KissButton->setIconSize(QSize(128, 128));
}
return _KissButton;
}
QString AccountPanel::GetToolTip()
{
return _("Operations");
}
void AccountPanel::InitStatsGrid(User* user)
{
int i;
int nb_categories = user->GetCategoriesNumber();
DEFAULT_FONT(font);
if (!_statsGrid->rowCount())
{
_statsGrid->setColumnCount(2);
//_statsGrid->EnableEditing(false);
}
else
{
_statsGrid->clear();
}
_statsGrid->setRowCount(nb_categories+CATS_STATS+1); // Headers + blank + categories + non fix
_statsGrid->setItem(TOTAL_CREDIT, 0, new QTableWidgetItem(_("Total Credit")));
_statsGrid->setItem(TOTAL_DEBIT, 0, new QTableWidgetItem(_("Total Debit")));
for(i=0; i<nb_categories; i++)
{
if (i)
{
_statsGrid->setItem(CATS_STATS+i+1, 0, new QTableWidgetItem(_categories[i]));
_statsGrid->setItem(CATS_STATS+i+1, 1, new QTableWidgetItem(""));
_statsGrid->item(CATS_STATS+i+1, 1)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
}
else
{
_statsGrid->setItem(CATS_STATS+i, 0, new QTableWidgetItem(_categories[i]));
_statsGrid->setItem(CATS_STATS+i, 1, new QTableWidgetItem(""));
_statsGrid->item(CATS_STATS+i, 1)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
}
}
font.setBold(true);
_statsGrid->setItem(CUR_CREDIT, 0, new QTableWidgetItem(_("Cur Credit")));
_statsGrid->setItem(CUR_DEBIT, 0, new QTableWidgetItem(_("Cur Debit")));
_statsGrid->setItem(TOTAL_CREDIT, 0, new QTableWidgetItem(_("Total Credit")));
_statsGrid->setItem(TOTAL_DEBIT, 0, new QTableWidgetItem(_("Total Debit")));
_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->item(CUR_DEBIT, 0)->setFont(font);
_statsGrid->item(CUR_CREDIT, 0)->setFont(font);
_statsGrid->item(BALANCE, 0)->setFont(font);
_statsGrid->item(BALANCE, 1)->setFont(font);
_statsGrid->item(CUR_CREDIT, 1)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
_statsGrid->item(CUR_DEBIT, 1)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
_statsGrid->item(TOTAL_CREDIT, 1)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
_statsGrid->item(TOTAL_DEBIT, 1)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
_statsGrid->item(BALANCE, 1)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
_statsGrid->item(NON_FIX, 1)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
_accountsGrid->resizeColumnToContents(0);
}
void AccountPanel::ChangeUser()
{
User* user = _kiss->GetUser();
int curYear = -1;
QDate curDate = QDate::currentDate();
QTreeWidgetItem* curNode=NULL, *node;
std::map<int, std::vector<int> > ops;
std::map<int, std::vector<int> >::iterator it;
ops = _kiss->GetAllOperations();
InitStatsGrid(user);
_tree->clear();
if (ops.size())
{
for(it = ops.begin(); it != ops.end(); it++)
{
node = new QTreeWidgetItem(QStringList(QString::number(it->first)));
if ((int)it->first <= curDate.year())
{
curYear = it->first;
curNode = node;
}
_tree->addTopLevelItem(node);
}
if (curYear != -1)
{
_tree->setCurrentItem(curNode);
LoadYear(curYear);
}
}
else
{
curNode = new QTreeWidgetItem(QStringList(QString::number(curDate.year())));
_tree->addTopLevelItem(curNode);
}
layout();
}
void AccountPanel::LoadYear(int year, bool showMonth)
{
User* user = _kiss->GetUser();
int curMonth = -1;
QTreeWidgetItem* parentNode, *curMonthNode = 0;
std::map<int, std::vector<int> > ops ;
std::vector<int>::iterator it;
if (user->_operations[year] && _tree->currentItem()->childCount())
{
if (showMonth)
ShowMonth(-1, year);
return;
}
_curYear = year ;
_kiss->LoadYear(year);
ops = _kiss->GetAllOperations();
parentNode = _tree->currentItem();
if (!parentNode)
parentNode = _tree->topLevelItem(0);
for (it = ops[year].begin(); it != ops[year].end(); it++)
{
if (!curMonthNode)
{
curMonth = *it;
curMonthNode = new QTreeWidgetItem(QStringList(wxUI::months[*it]));
parentNode->addChild(curMonthNode);
}
else
parentNode->addChild(new QTreeWidgetItem(QStringList(wxUI::months[*it])));
}
_tree->expandItem(parentNode);
layout();
if (showMonth)
{
_tree->setCurrentItem(curMonthNode);
ShowMonth(curMonth, year);
}
_wxUI->layout();
}
void AccountPanel::ShowMonth(int month, int year)
{
// std::vector<Operation> operations;
// _fixCosts = 0;
User* user = _kiss->GetUser();
// std::vector<Category>::iterator categoryIt;
std::map<unsigned int, std::vector<Operation> >::iterator monthIt;
QDate curDate = QDate::currentDate();
QDate dateStart = QDate::currentDate();
QDate dateEnd = QDate::currentDate();
if (month == -1)
{
// Near month
if (year == curDate.year())
{
for (monthIt = user->_operations[year]->begin(); monthIt != user->_operations[year]->end(); monthIt++)
{
if ((int)monthIt->first <= curDate.month())
{
month = monthIt->first;
}
}
}
// First month
if (month == -1)
{
monthIt = user->_operations[year]->begin();
if (user->_operations[year]->size() == 0 && year == curDate.year())
month = curDate.month();
else
month = monthIt->first;
}
}
_curYear = year;
_curMonth = month;
_wxUI->setWindowTitle(user->_name + " - " + wxUI::months[month] + " " + QString::number(year));
// if (_grid->GetNumberRows() > 1)
// _grid->DeleteRows(1, _grid->GetNumberRows()-1);
// Operations are ordered
_curOperations = &((*user->_operations[year])[month]);
_grid->LoadOperations(_curOperations, _curMonth, _curYear);
disconnect(_accountsGrid, SIGNAL(cellChanged(int, int)), this, SLOT(OnAccountModified(int, int)));
InitAccountsGrid(user, month, year);
connect(_accountsGrid, SIGNAL(cellChanged(int, int)), this, SLOT(OnAccountModified(int, int)));
dateStart.setDate(_curYear, _curMonth+1, 1);
dateEnd.setDate(_curYear, _curMonth+1, dateStart.daysInMonth());
_calendar->setDateRange(dateStart, dateEnd);
if ((curDate.month()-1) == month && curDate.year() == year)
_calendar->showToday();
else if ((curDate.month()-1) > month || curDate.year() > year)
_calendar->setSelectedDate (dateEnd) ;
else if ((curDate.month()-1) < month || curDate.year() < year)
_calendar->setSelectedDate(dateStart) ;
UpdateStats();
layout();
}
void AccountPanel::InitAccountsGrid(User* user, int month, int year)
{
std::vector<Account>::iterator it;
int curLine = 0;
double value;
int i, nbAccounts;
QTableWidgetItem* item;
QString v;
DEFAULT_FONT(font);
font.setBold(true);
if (_accountsGrid->rowCount())
_accountsGrid->clear();
_accountsGrid->setHorizontalHeaderItem(ACCOUNT_NUMBER, new QTableWidgetItem(_("Account number")));
_accountsGrid->setHorizontalHeaderItem(ACCOUNT_NAME, new QTableWidgetItem(_("Account name")));
_accountsGrid->setHorizontalHeaderItem(ACCOUNT_INIT, new QTableWidgetItem(_("Initial value")));
_accountsGrid->setHorizontalHeaderItem(ACCOUNT_CUR, new QTableWidgetItem(_("Current value")));
_accountsGrid->setHorizontalHeaderItem(ACCOUNT_FINAL, new QTableWidgetItem(_("Final value")));
for(i=0; i<NUMBER_COLS_ACCOUNTS; i++)
{
_accountsGrid->horizontalHeaderItem(i)->setFont(font);
}
FloatDelegate* floatEditor = new FloatDelegate(_accountsGrid);
_accountsGrid->setItemDelegateForColumn(ACCOUNT_INIT, floatEditor);
nbAccounts = 0;
for (it = user->_accounts.begin(); it != user->_accounts.end(); it++)
{
if (!it->hidden) nbAccounts++;
}
_accountsGrid->setRowCount(nbAccounts);
for (it = user->_accounts.begin(); it != user->_accounts.end(); it++, curLine++)
{
if (it->hidden)
{
value = _kiss->GetAccountAmount(it->id, month, year);
_accountsInitValues[it->id] = value;
curLine--;
continue;
}
if (it->shared)
_accountsGrid->setItem(curLine, ACCOUNT_NUMBER, new QTableWidgetItem(it->number + "*"));
else
_accountsGrid->setItem(curLine, ACCOUNT_NUMBER, new QTableWidgetItem(it->number));
_accountsGrid->setItem(curLine, ACCOUNT_NAME, new QTableWidgetItem(it->name));
value = _kiss->GetAccountAmount(it->id, month, year);
_accountsGrid->setItem(curLine, ACCOUNT_INIT, new QTableWidgetItem(v.sprintf("%.2lf", value)));
_accountsGrid->setItem(curLine, ACCOUNT_CUR, new QTableWidgetItem(""));
_accountsGrid->setItem(curLine, ACCOUNT_FINAL, new QTableWidgetItem(""));
for (i=0; i<NUMBER_COLS_ACCOUNTS; i++)
{
item = _accountsGrid->item(curLine, i);
if (i != ACCOUNT_INIT)
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
if (i == ACCOUNT_CUR)
item->setFont(font);
}
_accountsInitValues[it->id] = value;
_accountsGrid->item(curLine, ACCOUNT_INIT)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
_accountsGrid->item(curLine, ACCOUNT_CUR)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
_accountsGrid->item(curLine, ACCOUNT_FINAL)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
}
_accountsGrid->resizeColumnsToContents();
}
void AccountPanel::UpdateStats()
{
int i;
User* user = _kiss->GetUser();
std::vector<Operation>::iterator it;
double curCredit, curDebit, totalCredit, totalDebit, balance, value, value2, percents;
std::map<int, double> curAccountAmount, finalAccountAmount;
std::map<int, double>::iterator doubleIt;
std::map<int, int>::iterator intIt;
std::vector<Account>::iterator accountIt;
unsigned int day;
int mode;
std::map<int, double>* notChecked = 0;
std::map<int, double>* virtuals = 0;
Account account;
Operation op;
bool blocked_account ;
QString v;
_inModification = true;
if (_virtual->isChecked()) mode = VIRTUAL_MODE;
else if (_real->isChecked()) mode = REAL_MODE;
else if (_check->isChecked()) mode = CHECK_MODE;
curCredit = curDebit = totalCredit = totalDebit = percents = 0.0;
if (mode == CHECK_MODE)
notChecked = _kiss->GetNotChecked(_curMonth, _curYear);
if (mode == REAL_MODE || mode == CHECK_MODE)
virtuals = _kiss->GetVirtualAmount(_curMonth, _curYear);
day = _calendar->selectedDate().day()-1;
for (i=0; i<user->GetCategoriesNumber(); i++)
_categoriesValues[i] = 0.0;
for (doubleIt=_accountsInitValues.begin(); doubleIt!=_accountsInitValues.end(); doubleIt++)
{
curAccountAmount[doubleIt->first] = _accountsInitValues[doubleIt->first];
finalAccountAmount[doubleIt->first] = _accountsInitValues[doubleIt->first];
if (mode == REAL_MODE || mode == CHECK_MODE)
{
curAccountAmount[doubleIt->first] += -(*virtuals)[doubleIt->first];
finalAccountAmount[doubleIt->first] += -(*virtuals)[doubleIt->first];
}
}
for (it=_curOperations->begin(); it!=_curOperations->end(); it++)
{
if (it->meta) continue;
op = *it;
blocked_account = false;
// A credit on a blocked account must be considered as a debit
if (op.transfert && op.amount > 0)
{
account = user->GetAccount(op.account);
if (account.blocked)
{
op.amount = -op.amount;
op.transfert = 0;
blocked_account = true;
}
}
switch(mode)
{
case VIRTUAL_MODE:
if (op.amount >= 0)
{
if (!op.transfert)
totalCredit += op.amount;
if (day >= op.day)
{
if (!op.transfert)
curCredit += op.amount;
curAccountAmount[op.account] += op.amount;
}
finalAccountAmount[op.account] += op.amount;
}
else
{
if (!op.transfert && user->GetCategoryName(op.category) != _("Unknown"))
_categoriesValues[_categoriesIndexes[user->GetCategoryName(op.category)]] += -op.amount ;
if (!op.transfert)
totalDebit += -op.amount;
if (blocked_account)
op.amount = -op.amount;
if (day >= op.day)
{
if (!op.transfert)
curDebit += -op.amount;
curAccountAmount[op.account] += op.amount;
}
finalAccountAmount[op.account] += op.amount;
}
break;
case REAL_MODE:
if (op.amount >= 0)
{
if (!op.transfert)
totalCredit += op.amount;
if (day >= op.day)
{
if (!op.transfert)
curCredit += op.amount;
if (!op._virtual)
curAccountAmount[op.account] += op.amount;
}
if (!op._virtual)
finalAccountAmount[op.account] += op.amount;
}
else
{
if (!op.transfert && user->GetCategoryName(op.category) != _("Unknown"))
_categoriesValues[_categoriesIndexes[user->GetCategoryName(op.category)]] += -op.amount ;
if (!op.transfert && !op._virtual)
totalDebit += -op.amount;
if (blocked_account)
op.amount = -op.amount;
if (day >= op.day)
{
if (!op.transfert && !op._virtual)
curDebit += -op.amount;
if (!op._virtual)
curAccountAmount[op.account] += op.amount;
}
if (!op._virtual)
finalAccountAmount[op.account] += op.amount;
}
break;
case CHECK_MODE:
if (op.amount >= 0)
{
if (!op.transfert && !op._virtual)
totalCredit += op.amount;
if (day >= op.day)
{
if (!op.transfert && !op._virtual)
curCredit += op.amount;
if (op.checked && !op._virtual)
curAccountAmount[op.account] += op.amount;
}
if (op.checked && !op._virtual)
finalAccountAmount[op.account] += op.amount;
}
else
{
if (!op.transfert && user->GetCategoryName(op.category) != _("Unknown"))
_categoriesValues[_categoriesIndexes[user->GetCategoryName(op.category)]] += -op.amount ;
if (!op.transfert && !op._virtual)
totalDebit += -op.amount;
if (blocked_account)
op.amount = -op.amount;
if (day >= op.day)
{
if (!op.transfert && !op._virtual)
curDebit += -op.amount;
if (op.checked && !op._virtual)
curAccountAmount[op.account] += op.amount;
}
if (op.checked && !op._virtual)
finalAccountAmount[op.account] += op.amount;
}
break;
}
}
balance = totalCredit - totalDebit;
_statsGrid->item(CUR_CREDIT, 1)->setText(v.sprintf("%.2lf", curCredit));
_statsGrid->item(CUR_DEBIT, 1)->setText(v.sprintf("%.2lf", curDebit));
_statsGrid->item(TOTAL_CREDIT, 1)->setText(v.sprintf("%.2lf", totalCredit));
_statsGrid->item(TOTAL_DEBIT, 1)->setText(v.sprintf("%.2lf", totalDebit));
_statsGrid->item(BALANCE, 1)->setText(v.sprintf("%.2lf", balance));
_statsGrid->item(BALANCE, 1)->setForeground((balance >= 0) ? QBrush(Qt::green) : QBrush(Qt::red));
KDChart::Legend* legend = _pie->legend();
for(i=0; i<user->GetCategoriesNumber(); i++)
{
if (totalDebit != 0)
percents = ((double) (_categoriesValues[i]*100))/totalDebit;
else
percents = 0.0;
if (i)
_statsGrid->item(CATS_STATS+i+1, 1)->setText(v.sprintf("%.2lf (%02d %%)", _categoriesValues[i], (int)percents));
else
_statsGrid->item(CATS_STATS+i, 1)->setText(v.sprintf("%.2lf (%02d %%)", _categoriesValues[i], (int)percents));
QVector< double > vec;
vec << _categoriesValues[i];
_pie->setDataset( i, vec, _categories[i] );
if (_categoriesValues[i] == 0.0)
legend->setDatasetHidden(i, true);
else
legend->setDatasetHidden(i, false);
// _dataset->setData(_dataset->index(i, 1, QModelIndex()), _categoriesValues[i]);
}
value = totalDebit - _categoriesValues[0];
if (totalDebit != 0)
percents = ((double) (value*100))/totalDebit;
else
percents = 0.0;
_statsGrid->item(NON_FIX, 1)->setText(v.sprintf("%.2lf (%02d %%)", value, (int)percents));
for (i=0, accountIt=user->_accounts.begin(); accountIt!=user->_accounts.end(); accountIt++, i++)
{
if (accountIt->hidden)
{
i--;
continue;
}
if (mode != CHECK_MODE)
{
value = _accountsInitValues[accountIt->id];
if (mode == REAL_MODE)
value -= (*virtuals)[accountIt->id];
_accountsGrid->item(i, ACCOUNT_INIT)->setText(v.sprintf("%.2lf", value));
value = curAccountAmount[accountIt->id];
_accountsGrid->item(i, ACCOUNT_CUR)->setText(v.sprintf("%.2lf", value));
_accountsGrid->item(i, ACCOUNT_CUR)->setForeground((value >= 0) ? QBrush(Qt::black) : QBrush(Qt::red));
value = finalAccountAmount[accountIt->id];
_accountsGrid->item(i, ACCOUNT_FINAL)->setText(v.sprintf("%.2lf", value));
}
else
{
value = _accountsInitValues[accountIt->id] - (*virtuals)[accountIt->id];
value2 = (*notChecked)[accountIt->id];
_accountsGrid->item(i, ACCOUNT_INIT)->setText(v.sprintf("%.2lf (%.2lf)", value, value-value2));
value = curAccountAmount[accountIt->id];
_accountsGrid->item(i, ACCOUNT_CUR)->setText(v.sprintf("%.2lf (%.2lf)", value, value-value2));
_accountsGrid->item(i, ACCOUNT_CUR)->setForeground((value >= 0) ? QBrush(Qt::black) : QBrush(Qt::red));
value = finalAccountAmount[accountIt->id];
_accountsGrid->item(i, ACCOUNT_FINAL)->setText(v.sprintf("%.2lf (%.2lf)", value, value-value2));
}
}
_accountsGrid->resizeColumnToContents(ACCOUNT_INIT);
_accountsGrid->resizeColumnToContents(ACCOUNT_CUR);
_accountsGrid->resizeColumnToContents(ACCOUNT_FINAL);
if (notChecked) delete notChecked;
if (virtuals) delete virtuals;
_statsGrid->resizeColumnToContents(1);
layout();
_inModification = false;
}
void AccountPanel::OnOperationModified()
{
UpdateStats();
layout();
}
void AccountPanel::OnAccountModified(int row, int column)
{
User* user = _kiss->GetUser();
double amount;
int id = user->GetAccountId(_accounts[row]);
if (_inModification || column != ACCOUNT_INIT) return;
amount = _accountsGrid->item(row, column)->text().toDouble();
_kiss->SetAccountAmount(id, _curMonth, _curYear, amount);
_accountsInitValues[id] = amount;
UpdateStats();
}
void AccountPanel::OnTreeRightClick(const QPoint & pos)
{
QMenu menu(this);
menu.addAction(_("Generate month"), this, SLOT(OnMenuGenerate()));
menu.addSeparator();
if (_tree->columnCount() >= 1)
menu.addAction(_("Delete"), this, SLOT(OnMenuDelete()));
menu.exec(QCursor::pos());
}
void AccountPanel::OnTreeChange (QTreeWidgetItem * item, int column)
{
int month=-1, year;
int i;
QString monthString;
item = _tree->currentItem ();
if (!item) return;
monthString = item->text(column);
for (i=0; i<12; i++)
{
if (monthString == wxUI::months[i])
{
month = i;
break;
}
}
if (month == -1)
{
year = monthString.toInt();
// Error
if (year == 0)
{
return;
}
if (year == _curYear)
{
return;
}
// _tree.CollapseAll();
// _tree.Expand(event.GetItem());
LoadYear(year, true);
}
else
{
item = item->parent();
year = item->text(column).toInt();
// Error
if (year == 0)
{
return;
}
if (year != _curYear || month != _curMonth)
{
ShowMonth(month, year);
}
}
}
void AccountPanel::GetTreeSelection(int* month, int* year)
{
QString monthString;
int i;
bool ok;
*month = -1; *year = -1;
monthString = _tree->currentItem()->text(0);
for (i=0; i<12; i++)
if (monthString == wxUI::months[i])
{
*month = i;
break;
}
if (*month == -1)
{
*year = monthString.toInt(&ok);
// Error
if (!ok)
{
*month = -1;
*year = -1;
return;
}
}
else
{
*year = _tree->currentItem()->parent()->text(0).toInt(&ok);
// Error
if (!ok)
{
*month = -1;
*year = -1;
return;
}
}
}
void AccountPanel::OnMenuGenerate()
{
int month, year;
QDate curDate = QDate::currentDate();
GetTreeSelection(&month, &year);
if (month == -1 && year == curDate.year())
{
month = _curMonth;
}
_wxUI->setEnabled(false);
GenerateDialog g(_kiss, _wxUI, month, year);
g.setModal(true);
g.exec();
_wxUI->setEnabled(true);
}
void AccountPanel::OnMenuDelete()
{
int month, year, i;
QString message;
QTreeWidgetItem* curNode, *node ;
std::map<int, std::vector<int> > ops ;
GetTreeSelection(&month, &year);
ops = _kiss->GetAllOperations();
if (ops.size() == 1 && (ops[year].size() == 1 || month == -1))
{
QMessageBox::critical(0, _("Error"), _("It must be at least one month !"));
return;
}
message = _("Are you sure want to delete ");
if (month != -1)
message += wxUI::months[month] + " ";
message += QString::number(year);
message += _(" operations ?");
if (QMessageBox::question(0, "KissCount", message, QMessageBox::Yes|QMessageBox::No) == QMessageBox::No)
return;
curNode = _tree->currentItem();
if (ops[year].size() == 1 && month != -1)
curNode = curNode->parent();
_kiss->DeleteOperations(month, year);
i = _tree->indexOfTopLevelItem(curNode);
if (i == -1)
{
node = _tree->itemBelow(curNode);
if (!node)
node = _tree->itemAbove(curNode);
curNode->parent()->removeChild(curNode);
_tree->setCurrentItem(node);
}
else
{
delete _tree->takeTopLevelItem(i);
if (i) i--;
_tree->setCurrentItem(_tree->topLevelItem(i));
curNode = _tree->topLevelItem(i);
if (!curNode->childCount())
LoadYear(curNode->text(0).toInt());
_tree->setCurrentItem(curNode->child(curNode->childCount()-1));
}
if (!node)
ChangeUser();
else
{
GetTreeSelection(&month, &year);
if (month == -1)
month = ops[year][0];
ShowMonth(month, year);
_wxUI->NeedReload();
}
}
void AccountPanel::GenerateMonth(int month, int year)
{
QString s;
const QString syear = s.sprintf("%d", year);
QList<QTreeWidgetItem *> items = _tree->findItems(syear, Qt::MatchExactly|Qt::MatchRecursive);
QTreeWidgetItem *root, *itemYear = NULL, *itemMonth;
std::map<int, std::vector<int> > ops ;
std::vector<int>::iterator it ;
int i;
ops = _kiss->GetAllOperations();
// Year not found
if (items.size() == 0)
{
for(i=0; i<_tree->topLevelItemCount(); i++)
{
root = _tree->topLevelItem(i);
if (root->text(0).toInt() > year)
break;
}
itemYear = new QTreeWidgetItem(QStringList(syear));
_tree->insertTopLevelItem(i, itemYear);
_tree->setCurrentItem(itemYear);
}
else
itemYear = items[0];
for(i=0, it = ops[year].begin(); it != ops[year].end(); it++, i++)
{
if (*it > month)
break;
}
if (i) i--;
itemMonth = new QTreeWidgetItem(QStringList(wxUI::months[month]));
itemYear->insertChild(i, itemMonth);
_tree->setCurrentItem(itemMonth);
ShowMonth(month, year);
_wxUI->NeedReload();
}
void AccountPanel::OnShow()
{
User* user = _kiss->GetUser();
if (_curMonth != -1)
_wxUI->setWindowTitle(user->_name + " - " + wxUI::months[_curMonth] + " " + QString::number(_curYear));
else
_wxUI->setWindowTitle(user->_name);
}
void AccountPanel::OnCalendarChange()
{
UpdateStats();
}
void AccountPanel::OnModeChange()
{
UpdateStats();
}
void AccountPanel::OnGroup()
{
if (_grid)
_grid->Group();
}
void AccountPanel::OnUnGroup()
{
if (_grid)
_grid->UnGroup();
}
void AccountPanel::OnUpdateNextMonths()
{
double* deltas, *cur_amounts, amount;
int i, a;
User* user = _kiss->GetUser();
bool had_values, accounts_updated = false;
int last_month = 0, last_year = 0, account_updated = 0;
std::map<int, std::vector<int> > operations;
deltas = new double[user->_accounts.size()] ;
cur_amounts = new double[user->_accounts.size()] ;
operations = _kiss->GetAllOperations();
if (_curMonth == 11)
{
last_month = 0;
last_year = _curYear+1;
}
else
{
last_month = _curMonth+1;
last_year = _curYear;
}
for (i=0; i<(int)user->_accounts.size(); i++)
{
deltas[i] = _kiss->GetAccountAmount(user->_accounts[i].id, _curMonth, _curYear);
cur_amounts[i] = deltas[i] += _kiss->CalcAccountAmount(user->_accounts[i].id, _curMonth, _curYear, &had_values);
for (a=0; a<(int)operations[last_year].size(); a++)
if (operations[last_year][a] == last_month) break;
if (a == (int)operations[last_year].size())
{
deltas[i] = 0;
continue;
}
amount = _kiss->GetAccountAmount(user->_accounts[i].id, last_month, last_year);
deltas[i] -= amount;
account_updated++;
}
if (!account_updated)
goto end;
last_month = _curMonth;
last_year = _curYear;
while (1)
{
account_updated = 0;
if (last_month == 11)
{
last_month = 0;
last_year = last_year+1;
}
else
last_month++;
for (i=0; i<(int)user->_accounts.size(); i++)
{
if (deltas[i] == 0.0) continue;
amount = _kiss->GetAccountAmount(user->_accounts[i].id, last_month, last_year);
if ((cur_amounts[i] - amount) != deltas[i]) continue;
cur_amounts[i] = amount + deltas[i];
_kiss->SetAccountAmount(user->_accounts[i].id, last_month, last_year, cur_amounts[i]);
cur_amounts[i] += _kiss->CalcAccountAmount(user->_accounts[i].id, last_month, last_year, &had_values);
account_updated++;
}
if (!account_updated) break;
accounts_updated = true;
}
if (last_month == 0)
{
last_month = 11;
last_year--;
}
else
last_month--;
end:
if (accounts_updated)
{
QString message = _("Accounts updated until ") + wxUI::months[last_month] + " " + QString::number(last_year);
QMessageBox::information(0, "KissCount", message);
}
else
QMessageBox::information(0, "KissCount", _("Any account updated !"));
delete[] deltas;
delete[] cur_amounts;
}