/*
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 "AccountPanel.hpp"
#include "grid/FloatDelegate.hpp"
#include "GenerateDialog.hpp"
#include "SnapshotsDialog.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, CATS_STATS};
enum {VIRTUAL_MODE=0, REAL_MODE, CHECK_MODE};
AccountPanel::AccountPanel(KissCount* kiss, wxUI *parent, bool lowResolution) :
KissPanel(kiss, parent, lowResolution), _curMonth(-1), _curYear(-1), _inModification(false)
{
Init(kiss, parent, 0);
}
AccountPanel::AccountPanel(KissCount* kiss, wxUI *parent, bool lowResolution, int month=-1, int year=-1, int mode=VIRTUAL_MODE) : KissPanel(kiss, parent, lowResolution), _curMonth(month), _curYear(year), _inModification(false)
{
Init(kiss, parent, mode);
}
void AccountPanel::Init(KissCount* kiss, wxUI *parent, int curMode)
{
QHBoxLayout *hbox = new QHBoxLayout;
QHBoxLayout *hbox2 = new QHBoxLayout;
QHBoxLayout *hbox3 = new QHBoxLayout;
QHBoxLayout *hbox4 = new QHBoxLayout;
QVBoxLayout *vbox = new QVBoxLayout;
QVBoxLayout *vbox2 = new QVBoxLayout;
QVBoxLayout *vbox3 = new QVBoxLayout;
int i;
User* user = _kiss->GetUser();
std::vector::iterator accountIt;
std::vector::iterator categoryIt;
std::vector::iterator tagIt;
_icons[KissPanel::LOW_RES_ICON] = USER_LOW_ICON;
_icons[KissPanel::HIGH_RES_ICON] = USER_ICON;
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 &)));
_calendar = new QCalendarWidget(this);
_calendar->setGridVisible(false);
_calendar->setFirstDayOfWeek(Qt::Monday);
_calendar->setNavigationBarVisible(false);
_calendar->setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader);
_calendar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
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;
}
_categoriesValues = new int[user->GetCategoriesNumber()];
_tags = new QString[user->GetTagsNumber()] ;
for(i=0, tagIt = user->_tags.begin();
tagIt != user->_tags.end();
tagIt++, i++)
{
_tags[i] = _(tagIt->name.toStdString().c_str()) ;
_tagsIndexes[tagIt->name] = i;
}
_tagsValues = new int[user->GetTagsNumber()];
_grid = new GridAccount(_kiss, this, true, true, true);
_grid->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
_grid->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
_accountsGrid = new QTableWidget(this);
_accountsGrid->setColumnCount(NUMBER_COLS_ACCOUNTS);
_accountsGrid->setRowCount(0);
_accountsGrid->verticalHeader()->setHidden(true);
_accountsGrid->resizeColumnsToContents();
_accountsGrid->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
_accountsGrid->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
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::Minimum);
_statsGrid->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
_costRepartitionBanner = new CostRepartitionBanner(_kiss, this, _categories);
QGroupBox *groupBox = new QGroupBox(_("Mode"));
_virtual = new QRadioButton(_("Virtual"));
_real = new QRadioButton(_("Real"));
_check = new QRadioButton(_("Check"));
switch(curMode)
{
case VIRTUAL_MODE: _virtual->setChecked(true); break;
case REAL_MODE: _real->setChecked(true); break;
case CHECK_MODE: _check->setChecked(true); break;
default: _virtual->setChecked(true); break;
}
{
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"));
QPushButton* buttonSnapshots = new QPushButton(_("Snapshots"));
connect(buttonGroup, SIGNAL(clicked()), this, SLOT(OnGroup()));
connect(buttonUnGroup, SIGNAL(clicked()), this, SLOT(OnUnGroup()));
connect(buttonUpdateNextMonths, SIGNAL(clicked()), this, SLOT(OnUpdateNextMonths()));
connect(buttonSnapshots, SIGNAL(clicked()), this, SLOT(OnSnapshots()));
vbox3->addWidget(_tree);
vbox3->addWidget(buttonUpdateNextMonths);
vbox3->addStretch(1);
vbox3->addWidget(_calendar);
vbox3->addStretch(1);
vbox3->addWidget(buttonGroup);
vbox3->addWidget(buttonUnGroup);
vbox3->addStretch(1);
vbox3->addWidget(buttonSnapshots);
vbox3->addStretch(1);
vbox3->addWidget(groupBox);
hbox->addLayout(vbox3);
hbox2->addStretch(3);
hbox2->addWidget(_accountsGrid, 2);
hbox2->addStretch(3);
vbox2->addLayout(hbox2);
hbox4->addStretch();
hbox4->addWidget(_grid);
hbox4->addStretch();
vbox2->addLayout(hbox4, 1);
hbox->addLayout(vbox2);
hbox3->addStretch(0);
hbox3->addWidget(_statsGrid);
hbox3->addStretch(0);
vbox->addLayout(hbox3);
vbox->addWidget(_costRepartitionBanner);
hbox->addLayout(vbox);
hbox->setStretch(0, 1);
hbox->setStretch(1, 4);
hbox->setStretch(2, 1);
ChangeUser();
layout();
}
AccountPanel::~AccountPanel()
{
delete[] _categoriesValues;
delete[] _categories;
if (_tagsValues)
delete[] _tagsValues;
if (_tags)
delete[] _tags;
delete[] _accounts;
}
KissPanel* AccountPanel::CreatePanel()
{
int mode;
if (_virtual->isChecked()) mode = VIRTUAL_MODE;
else if (_real->isChecked()) mode = REAL_MODE;
else if (_check->isChecked()) mode = CHECK_MODE;
return new AccountPanel(_kiss, _wxUI, _lowResolution, _curMonth, _curYear, mode);
}
QString AccountPanel::GetToolTip()
{
return _("Operations");
}
void AccountPanel::InitStatsGrid(User* user)
{
DEFAULT_FONT(font);
if (!_statsGrid->rowCount())
{
_statsGrid->setColumnCount(2);
//_statsGrid->EnableEditing(false);
}
else
{
_statsGrid->clear();
}
_statsGrid->setRowCount(CATS_STATS); // Headers
_statsGrid->setItem(TOTAL_CREDIT, 0, new QTableWidgetItem(_("Total Credit")));
_statsGrid->setItem(TOTAL_DEBIT, 0, new QTableWidgetItem(_("Total Debit")));
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(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->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->resizeColumnToContents(0);
_costRepartitionBanner->Reset();
}
void AccountPanel::ChangeUser()
{
User* user = _kiss->GetUser();
int curYear = -1, year;
QDate curDate = QDate::currentDate();
QTreeWidgetItem* curNode=0, *node;
std::map > ops;
std::map >::iterator it;
ops = _kiss->GetAllOperations();
InitStatsGrid(user);
_tree->clear();
if (ops.size())
{
year = (_curYear == -1) ? curDate.year() : _curYear;
for(it = ops.begin(); it != ops.end(); it++)
{
node = new QTreeWidgetItem(QStringList(QString::number(it->first)));
if ((int)it->first <= year)
{
curYear = it->first;
curNode = node;
}
_tree->addTopLevelItem(node);
}
if (curYear != -1)
{
_tree->setCurrentItem(curNode);
LoadYear(curYear, true);
}
}
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 lastMonth = -1, month;
QTreeWidgetItem* parentNode, *curMonthNode = 0, *lastMonthNode = 0;
std::map > ops ;
std::vector::iterator it;
QDate curDate = QDate::currentDate();
if (user->_operations[year] && _tree->currentItem()->childCount())
{
if (showMonth)
ShowMonth(-1, year);
return;
}
_inModification = true;
_curYear = year ;
_kiss->LoadYear(year);
ops = _kiss->GetAllOperations();
parentNode = _tree->currentItem();
if (!parentNode)
parentNode = _tree->topLevelItem(0);
if (_curYear == curDate.year())
month = curDate.month()-1;
else
month = 11;
for (it = ops[year].begin(); it != ops[year].end(); it++)
{
lastMonthNode = new QTreeWidgetItem(QStringList(wxUI::months[*it]));
if (year == _curYear && *it == month)
curMonthNode = lastMonthNode;
lastMonth = *it;
parentNode->addChild(lastMonthNode);
}
_tree->expandItem(parentNode);
layout();
if (showMonth)
{
if (curMonthNode)
{
_tree->setCurrentItem(curMonthNode);
ShowMonth(month, year);
}
else
{
_tree->setCurrentItem(lastMonthNode);
ShowMonth(lastMonth, year);
}
}
_wxUI->layout();
_inModification = false;
}
void AccountPanel::ShowMonth(int month, int year)
{
// std::vector operations;
// _fixCosts = 0;
User* user = _kiss->GetUser();
// std::vector::iterator categoryIt;
std::map >::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+1 <= 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() == (_curMonth+1) && curDate.year() == year)
_calendar->setSelectedDate (curDate) ;
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::iterator it;
int curLine = 0;
int 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; ihorizontalHeaderItem(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 && it->validAt(month, year))
nbAccounts++;
}
_accountsGrid->setRowCount(nbAccounts);
for (it = user->_accounts.begin(); it != user->_accounts.end(); it++, curLine++)
{
if (it->hidden || !it->validAt(month, year))
{
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", (double)value/100)));
_accountsGrid->setItem(curLine, ACCOUNT_CUR, new QTableWidgetItem(""));
_accountsGrid->setItem(curLine, ACCOUNT_FINAL, new QTableWidgetItem(""));
for (i=0; iitem(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, nbDays, minimalValue;
User* user = _kiss->GetUser();
std::vector::iterator it;
int curCredit, curDebit, totalCredit, totalDebit, balance, value, value2, percents;
std::map finalAccountAmount;
std::map* curAccountAmounts; // For each day
std::map::iterator intIt;
std::vector::iterator accountIt;
unsigned int day;
int mode;
std::map* notChecked = 0;
std::map* virtuals = 0;
Account account;
Operation op;
bool force_debit;
QString v;
QDate selectedDate;
QTextCharFormat textFormat;
QBrush brush;
int minStartAccount = 0;
_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);
selectedDate = _calendar->selectedDate();
day = selectedDate.day()-1;
nbDays = selectedDate.daysInMonth();
curAccountAmounts = new std::map[nbDays];
for (i=0; iGetCategoriesNumber(); i++)
_categoriesValues[i] = 0.0;
for (intIt=_accountsInitValues.begin(); intIt!=_accountsInitValues.end(); intIt++)
{
finalAccountAmount[intIt->first] = _accountsInitValues[intIt->first];
for(i=0; ifirst] = _accountsInitValues[intIt->first];
if (mode == REAL_MODE || mode == CHECK_MODE)
{
for(i=0; ifirst] += -(*virtuals)[intIt->first];
finalAccountAmount[intIt->first] += -(*virtuals)[intIt->first];
}
}
for (it=_curOperations->begin(); it!=_curOperations->end(); it++)
{
if (it->meta) continue;
op = *it;
force_debit = false;
if ((mode == REAL_MODE || mode == CHECK_MODE) && op._virtual)
continue;
if (mode == CHECK_MODE && !op.checked)
continue;
account = user->GetAccount(op.account);
if (account.blocked)
{
if (op.transfert && op.amount > 0)
{
// A Transfert on a blocked account must be considered as a debit
op.amount = -op.amount;
// op.transfert = 0;
force_debit = true;
}
// else
// continue;
}
if (op.amount >= 0)
{
if (!op.transfert && !account.blocked)
totalCredit += op.amount;
if (day >= op.day)
{
if (!op.transfert && !account.blocked)
curCredit += op.amount;
}
}
else
{
if ((!op.transfert || force_debit) && user->GetCategoryName(op.category) != _("Unknown"))
_categoriesValues[_categoriesIndexes[user->GetCategoryName(op.category)]] += -op.amount ;
if (!op.transfert || force_debit)
totalDebit += -op.amount;
if (day >= op.day)
{
if (!op.transfert || force_debit)
curDebit += -op.amount;
}
if (force_debit)
op.amount = -op.amount;
}
finalAccountAmount[op.account] += op.amount;
curAccountAmounts[op.day][op.account] += op.amount;
for(i=op.day+1; iGetAccount(intIt->first).hidden && !user->GetAccount(intIt->first)._virtual)
{
minStartAccount = intIt->first;
break;
}
}
}
for(i=0; idateTextFormat(QDate(_curYear, _curMonth+1, i+1));
if (mode != CHECK_MODE)
{
minimalValue = curAccountAmounts[i][minStartAccount];
for (intIt=curAccountAmounts[i].begin(); intIt!=curAccountAmounts[i].end(); intIt++)
{
account = user->GetAccount(intIt->first);
if (account.hidden || account._virtual ||
!account.validAt(i, _curMonth, _curYear))
continue;
if (curAccountAmounts[i][intIt->first] < minimalValue)
minimalValue = curAccountAmounts[i][intIt->first];
}
if (minimalValue <= 0)
{
brush.setColor(Qt::red);
textFormat.setBackground(brush);
QDate date(_curYear, _curMonth+1, i+1);
if (date.dayOfWeek() == 6 || date.dayOfWeek() == 7)
{
brush.setColor(Qt::black);
textFormat.setForeground(brush);
}
}
else if (minimalValue <= user->GetAccountLimitValue()*100)
{
brush.setColor(user->GetAccountLimitColor());
textFormat.setBackground(brush);
}
else
{
textFormat.clearBackground();
}
}
else
{
textFormat.clearBackground();
}
_calendar->setDateTextFormat(QDate(_curYear, _curMonth+1, i+1), textFormat);
}
balance = totalCredit - totalDebit;
_statsGrid->item(CUR_CREDIT, 1)->setText(v.sprintf("%.2lf", (double)curCredit/100));
_statsGrid->item(CUR_DEBIT, 1)->setText(v.sprintf("%.2lf", (double)curDebit/100));
_statsGrid->item(TOTAL_CREDIT, 1)->setText(v.sprintf("%.2lf", (double)totalCredit/100));
_statsGrid->item(TOTAL_DEBIT, 1)->setText(v.sprintf("%.2lf", (double)totalDebit/100));
_statsGrid->item(BALANCE, 1)->setText(v.sprintf("%.2lf", (double)balance/100));
_statsGrid->item(BALANCE, 1)->setForeground((balance >= 0) ? QBrush(Qt::green) : QBrush(Qt::red));
for (i=0, accountIt=user->_accounts.begin(); accountIt!=user->_accounts.end(); accountIt++, i++)
{
if (accountIt->hidden || !accountIt->validAt(_curMonth, _curYear))
{
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", (double)value/100));
_accountsGrid->item(i, ACCOUNT_INIT)->setForeground((value >= 0) ? QBrush(Qt::black) : QBrush(Qt::red));
value = curAccountAmounts[day][accountIt->id];
_accountsGrid->item(i, ACCOUNT_CUR)->setText(v.sprintf("%.2lf", (double)value/100));
_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", (double)value/100));
_accountsGrid->item(i, ACCOUNT_FINAL)->setForeground((value >= 0) ? QBrush(Qt::black) : QBrush(Qt::red));
}
else
{
value = _accountsInitValues[accountIt->id] - (*virtuals)[accountIt->id];
value2 = (*notChecked)[accountIt->id];
_accountsGrid->item(i, ACCOUNT_INIT)->setText(v.sprintf("%.2lf (%.2lf)", (double)value/100, (double)(value-value2)/100));
_accountsGrid->item(i, ACCOUNT_INIT)->setForeground((value >= 0) ? QBrush(Qt::black) : QBrush(Qt::red));
value = curAccountAmounts[day][accountIt->id];
_accountsGrid->item(i, ACCOUNT_CUR)->setText(v.sprintf("%.2lf (%.2lf)", (double)value/100, (double)(value-value2)/100));
_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)", (double)value/100, (double)(value-value2)/100));
_accountsGrid->item(i, ACCOUNT_FINAL)->setForeground((value >= 0) ? QBrush(Qt::black) : QBrush(Qt::red));
}
}
_costRepartitionBanner->UpdateCosts(_categoriesValues, totalDebit);
_accountsGrid->resizeColumnToContents(ACCOUNT_INIT);
_accountsGrid->resizeColumnToContents(ACCOUNT_CUR);
_accountsGrid->resizeColumnToContents(ACCOUNT_FINAL);
if (notChecked) delete notChecked;
if (virtuals) delete virtuals;
delete[] curAccountAmounts;
_statsGrid->resizeColumnToContents(1);
layout();
_inModification = false;
}
void AccountPanel::OnOperationModified()
{
UpdateStats();
}
void AccountPanel::OnAccountModified(int row, int column)
{
User* user = _kiss->GetUser();
int amount;
int id = user->GetAccountId(_accounts[row]);
if (_inModification || column != ACCOUNT_INIT) return;
amount = _accountsGrid->item(row, column)->text().replace(".", "").toInt();
_kiss->SetAccountAmount(id, _curMonth, _curYear, amount);
_accountsInitValues[id] = amount;
UpdateStats();
NeedReload();
}
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;
if (_inModification) return;
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);
NeedReload();
}
void AccountPanel::OnMenuDelete()
{
int month, year, i;
QString message;
QTreeWidgetItem* curNode, *node ;
std::map > 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);
}
NeedReload();
}
void AccountPanel::GenerateMonth(int month, int year)
{
QString s;
const QString syear = s.sprintf("%d", year);
QList items = _tree->findItems(syear, Qt::MatchExactly|Qt::MatchRecursive);
QTreeWidgetItem *root, *itemYear = 0, *itemMonth;
std::map > ops ;
std::vector::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);
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()
{
int *cur_amounts, amount, i;
User* user = _kiss->GetUser();
bool has_values, accounts_updated = false;
int cur_month = 0, cur_year = 0, delta_computed = 0;
int last_month, last_year;
bool *valid_account;
cur_amounts = new int[user->_accounts.size()] ;
valid_account = new bool[user->_accounts.size()] ;
cur_month = _curMonth;
cur_year = _curYear;
for (i=0; i<(int)user->_accounts.size(); i++)
{
cur_amounts[i] = _kiss->GetAccountAmount(user->_accounts[i].id, cur_month, cur_year, &has_values, false);
valid_account[i] = has_values;
}
while (1)
{
delta_computed = 0;
for (i=0; i<(int)user->_accounts.size(); i++)
{
if (!valid_account[i]) continue;
cur_amounts[i] += _kiss->CalcAccountAmount(user->_accounts[i].id, cur_month, cur_year, &has_values);
if (has_values)
delta_computed++;
}
if (!delta_computed) break;
if (cur_month == 11)
{
cur_month = 0;
cur_year++;
}
else
cur_month++;
for (i=0; i<(int)user->_accounts.size(); i++)
{
if (!valid_account[i]) continue;
amount = _kiss->GetAccountAmount(user->_accounts[i].id, cur_month, cur_year, &has_values, false);
if (!has_values)
{
valid_account[i] = false;
continue;
}
if (amount != cur_amounts[i])
{
accounts_updated = true;
_kiss->SetAccountAmount(user->_accounts[i].id, cur_month, cur_year, cur_amounts[i]);
last_month = cur_month; last_year = cur_year;
}
}
}
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 !"));
NeedReload();
delete[] cur_amounts;
}
void AccountPanel::OnSnapshots()
{
SnapshotsDialog u(_kiss, _wxUI);
u.exec();
}