1560 lines
40 KiB
C++
1560 lines
40 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 <QtGui>
|
|
|
|
#include "GridAccount.hpp"
|
|
#include "TableViewDelegate.hpp"
|
|
#include "ChoiceDelegate.hpp"
|
|
#include "DateDelegate.hpp"
|
|
#include "FloatDelegate.hpp"
|
|
#include "FormulaDelegate.hpp"
|
|
#include "TabDelegate.hpp"
|
|
|
|
#define SET_ROW_COLOR(row, backcolor, forecolor) for(int i=0; i<NUMBER_COLS_OPS; i++) \
|
|
{ \
|
|
if (!this->item(row, i)) setItem(row, i, new QTableWidgetItem("")); \
|
|
this->item(row, i)->setBackground(backcolor); \
|
|
this->item(row, i)->setForeground(forecolor); \
|
|
}
|
|
|
|
#define SET_ROW_FONT(row, font) for(int i=0; i<NUMBER_COLS_OPS; i++) \
|
|
{ \
|
|
if (!this->item(row, i)) setItem(row, i, new QTableWidgetItem("")); \
|
|
this->item(row, i)->setFont(font); \
|
|
}
|
|
|
|
#define SET_READ_ONLY(item) item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
|
|
|
GridAccount::GridAccount(KissCount* kiss, QWidget *parent,
|
|
bool canAddOperation, bool setWeek, bool synchronizeWithDatabase)
|
|
: QTableWidget(parent), _fixCosts(0), _week1(0),
|
|
_week2(0), _week3(0), _week4(0), _week5(0), _canAddOperation(canAddOperation),
|
|
_parent(parent), _kiss(kiss), _setWeek(setWeek),
|
|
_databaseSynchronization(synchronizeWithDatabase), _loadOperations(false),
|
|
_curMonth(0), _curYear(0), _treeSignalMapper(this), _checkSignalMapper(this),
|
|
_deleteSignalMapper(this), _inModification(false), _completer(0)
|
|
{
|
|
DEFAULT_FONT(font);
|
|
int i;
|
|
User* user = _kiss->GetUser();
|
|
std::vector<Account>::iterator accountIt;
|
|
std::vector<Category>::iterator categoryIt;
|
|
QTableWidgetItem* item;
|
|
QLabel* label;
|
|
|
|
setColumnCount(NUMBER_COLS_OPS);
|
|
setRowCount(1);
|
|
verticalHeader()->setHidden(true);
|
|
horizontalHeader()->setHidden(true);
|
|
setShowGrid(false);
|
|
|
|
setColumnWidth (DESCRIPTION, columnWidth(DESCRIPTION)*3);
|
|
setFont(font);
|
|
|
|
font.setBold(true);
|
|
QString colsName[] = {"", _("Description"), _("Date"), _("Debit"), _("Credit"), _("Category"), _("Account"), "", ""};
|
|
for(i=0; i<NUMBER_COLS_OPS; i++)
|
|
{
|
|
item = new QTableWidgetItem(colsName[i]);
|
|
item->setBackground(view::OWN_CYAN);
|
|
item->setFont(font);
|
|
SET_READ_ONLY(item);
|
|
item->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
|
|
setItem(0, i, item);
|
|
}
|
|
label = new QLabel();
|
|
label->setPixmap(QPixmap(DELETE_ICON));
|
|
label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
|
setCellWidget(0, OP_DELETE, label);
|
|
|
|
label = new QLabel();
|
|
label->setPixmap(QPixmap(CHECKED_ICON));
|
|
label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
|
setCellWidget(0, CHECKED, label);
|
|
|
|
_nbAccounts = 0;
|
|
for (accountIt = user->_accounts.begin();
|
|
accountIt != user->_accounts.end();
|
|
accountIt++)
|
|
{
|
|
if (!accountIt->hidden)
|
|
_nbAccounts++;
|
|
}
|
|
|
|
_accounts = new QString[_nbAccounts];
|
|
for (i=0,
|
|
accountIt = user->_accounts.begin();
|
|
accountIt != user->_accounts.end();
|
|
accountIt++, i++)
|
|
{
|
|
if (!accountIt->hidden)
|
|
_accounts[i] = accountIt->name;
|
|
else
|
|
i--;
|
|
}
|
|
|
|
_categories = new QString[user->GetCategoriesNumber()-1] ;
|
|
for(i=0, categoryIt = user->_categories.begin()+1;
|
|
categoryIt != user->_categories.end();
|
|
categoryIt++, i++)
|
|
{
|
|
_categories[i] = categoryIt->name ;
|
|
}
|
|
|
|
resizeColumnToContents(TREE);
|
|
resizeColumnToContents(CATEGORY);
|
|
resizeColumnToContents(OP_DATE);
|
|
resizeColumnToContents(ACCOUNT);
|
|
resizeColumnToContents(OP_DELETE);
|
|
resizeColumnToContents(CHECKED);
|
|
|
|
connect(&_treeSignalMapper, SIGNAL(mapped(int)), this, SLOT(OnMetaClicked(int)));
|
|
connect(&_checkSignalMapper, SIGNAL(mapped(int)), this, SLOT(OnCheckClicked(int)));
|
|
connect(&_deleteSignalMapper, SIGNAL(mapped(int)), this, SLOT(OnDeleteClicked(int)));
|
|
setItemDelegate(new TableViewDelegate(this));
|
|
connect(this, SIGNAL(cellChanged(int, int)), this, SLOT(OnOperationModified(int, int)));
|
|
}
|
|
|
|
GridAccount::~GridAccount()
|
|
{
|
|
delete[] _categories;
|
|
delete[] _accounts;
|
|
if (_completer)
|
|
delete _completer;
|
|
}
|
|
|
|
void GridAccount::ResetWeeks()
|
|
{
|
|
_week1 = _week2 = _week3 = _week4 = _week5 = 0;
|
|
}
|
|
|
|
void GridAccount::SetWeek(int week, int line) {
|
|
switch (week) {
|
|
case 1: _week1 = line; break;
|
|
case 2: _week2 = line; break;
|
|
case 3: _week3 = line; break;
|
|
case 4: _week4 = line; break;
|
|
case 5: _week5 = line; break;
|
|
}
|
|
}
|
|
|
|
Operation& GridAccount::GetOperation(int id) throw (OperationNotFound)
|
|
{
|
|
std::vector<Operation>::iterator it = std::find(_operations->begin(), _operations->end(), id);
|
|
|
|
if (it != _operations->end()) return *it;
|
|
|
|
throw OperationNotFound();
|
|
}
|
|
|
|
void GridAccount::UpdateOperation(Operation& op)
|
|
{
|
|
std::vector<Operation>::iterator it = std::find(_operations->begin(), _operations->end(), op.id);
|
|
|
|
if (it != _operations->end())
|
|
{
|
|
if (_databaseSynchronization)
|
|
_kiss->UpdateOperation(op);
|
|
*it = op;
|
|
}
|
|
}
|
|
|
|
int GridAccount::GetDisplayedRow(int id)
|
|
{
|
|
std::vector<Operation>::iterator it = std::find(_displayedOperations.begin(), _displayedOperations.end(), id);
|
|
|
|
if (it != _displayedOperations.end()) return it-_displayedOperations.begin();
|
|
|
|
return -1;
|
|
}
|
|
|
|
void GridAccount::ClearGrid()
|
|
{
|
|
std::vector<Operation> operations;
|
|
|
|
LoadOperations(&operations, 0, 0);
|
|
}
|
|
|
|
void GridAccount::LoadOperations(std::vector<Operation>* operations, int month, int year)
|
|
{
|
|
std::vector<Operation>::iterator it;
|
|
User* user = _kiss->GetUser();
|
|
int curLine = 0;
|
|
Operation NULLop;
|
|
QStringList list;
|
|
|
|
NULLop.id = 0;
|
|
|
|
_loadOperations = true;
|
|
_operations = operations;
|
|
_curMonth = month;
|
|
_curYear = year;
|
|
_displayedOperations.clear();
|
|
_displayedOperations.push_back(NULLop); // Header
|
|
_fixCosts = 0;
|
|
it = _operations->begin();
|
|
|
|
if (rowCount() > 1)
|
|
setRowCount(1);
|
|
|
|
if (_completer)
|
|
{
|
|
delete _completer;
|
|
_completer = 0;
|
|
}
|
|
|
|
if (_canAddOperation)
|
|
{
|
|
_kiss->GetHistory(month, year, list);
|
|
_completer = new QCompleter(list);
|
|
_completer->setCaseSensitivity(Qt::CaseInsensitive);
|
|
//_completer->setCompletionMode(QCompleter::InlineCompletion);
|
|
}
|
|
|
|
TabDelegate* descriptionEditor = new TabDelegate(this, &_displayedOperations, _completer);
|
|
setItemDelegateForColumn(DESCRIPTION, descriptionEditor);
|
|
|
|
ChoiceDelegate* categoryEditor = new ChoiceDelegate(this, _categories, user->GetCategoriesNumber()-1);
|
|
setItemDelegateForColumn(CATEGORY, categoryEditor);
|
|
ChoiceDelegate* accountEditor = new ChoiceDelegate(this, _accounts, _nbAccounts);
|
|
setItemDelegateForColumn(ACCOUNT, accountEditor);
|
|
|
|
DateDelegate* dateEditor = new DateDelegate(this, month+1, year);
|
|
setItemDelegateForColumn(OP_DATE, dateEditor);
|
|
|
|
FormulaDelegate* formulaEditor = new FormulaDelegate(this, &_displayedOperations);
|
|
setItemDelegateForColumn(DEBIT, formulaEditor);
|
|
setItemDelegateForColumn(CREDIT, formulaEditor);
|
|
|
|
if (_canAddOperation)
|
|
{
|
|
for (;it != _operations->end() && it->fix_cost; it++)
|
|
{
|
|
if (it->parent) continue;
|
|
|
|
if (_setWeek)
|
|
InsertOperationWithWeek(user, *it, ++curLine, true, it->month, it->year);
|
|
else
|
|
InsertOperation(user, *it, ++curLine, true, it->month, it->year);
|
|
}
|
|
|
|
InsertOperation(user, NULLop, ++curLine, true, month, year);
|
|
|
|
for (; it != _operations->end(); it++)
|
|
{
|
|
if (it->parent) continue;
|
|
|
|
if (_setWeek)
|
|
InsertOperationWithWeek(user, *it, ++curLine, false, it->month, it->year);
|
|
else
|
|
InsertOperation(user, *it, ++curLine, false, it->month, it->year);
|
|
}
|
|
|
|
InsertOperation(user, NULLop, ++curLine, false, month, year);
|
|
}
|
|
else
|
|
{
|
|
for (;it != _operations->end(); it++)
|
|
{
|
|
if (it->parent) continue;
|
|
|
|
InsertOperation(user, *it, ++curLine, it->fix_cost, it->month, it->year);
|
|
}
|
|
}
|
|
|
|
resizeColumnToContents(TREE);
|
|
resizeColumnToContents(CATEGORY);
|
|
resizeColumnToContents(OP_DATE);
|
|
resizeColumnToContents(ACCOUNT);
|
|
resizeColumnToContents(OP_DELETE);
|
|
resizeColumnToContents(CHECKED);
|
|
|
|
_loadOperations = false;
|
|
}
|
|
|
|
void GridAccount::ComputeWeeks()
|
|
{
|
|
std::vector<Operation>::iterator it;
|
|
int curLine, curWeek, week, i;
|
|
|
|
if (!_canAddOperation) return;
|
|
|
|
for (it = _displayedOperations.begin(), curLine=0;
|
|
it != _displayedOperations.end();
|
|
it++, curLine++)
|
|
{
|
|
if (it->id && !it->fix_cost) break;
|
|
}
|
|
|
|
if (it == _displayedOperations.end()) return;
|
|
|
|
ResetWeeks();
|
|
|
|
curWeek = QDate(it->year, it->month+1, it->day+1).weekNumber();
|
|
it++;
|
|
for (i=1; it != _displayedOperations.end(); it++, curLine++)
|
|
{
|
|
if (!it->id || it->parent) continue;
|
|
week = QDate(it->year, it->month+1, it->day+1).weekNumber();
|
|
if (week != curWeek)
|
|
{
|
|
SetWeek(i++, curLine);
|
|
curWeek = week;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GridAccount::InsertOperationWithWeek(User* user, Operation& op, int line, bool fix, int month, int year)
|
|
{
|
|
InsertOperation(user, op, line, fix, month, year);
|
|
|
|
if (op.id && !fix)
|
|
ComputeWeeks();
|
|
}
|
|
#include <QtDebug>
|
|
void GridAccount::InsertOperation(User* user, Operation& op, int line, bool fix, int month, int year)
|
|
{
|
|
std::vector<Operation>::iterator it;
|
|
std::vector<QString>::iterator it2;
|
|
int r, g, b;
|
|
double amount;
|
|
QColor color;
|
|
QDate curDate = QDate::currentDate();
|
|
QString description, v;
|
|
DEFAULT_FONT(font);
|
|
Category cat ;
|
|
Operation op2;
|
|
QTableWidgetItem* item;
|
|
QCheckBox* checkBox;
|
|
|
|
// // First is header
|
|
// if (op.id)
|
|
_displayedOperations.insert(_displayedOperations.begin()+line, op);
|
|
|
|
if (!user->_accounts.size()) return;
|
|
|
|
_inModification = true;
|
|
|
|
insertRow(line);
|
|
|
|
if (fix)
|
|
{
|
|
item = new QTableWidgetItem(_("Fix"));
|
|
setItem(line, CATEGORY, item);
|
|
SET_READ_ONLY(item);
|
|
_fixCosts++;
|
|
}
|
|
|
|
if (op.id)
|
|
{
|
|
cat = user->GetCategory(op.category);
|
|
|
|
description = op.description;
|
|
UNESCAPE_CHARS(description);
|
|
if (op.parent)
|
|
setItem(line, DESCRIPTION, new QTableWidgetItem(" " + description));
|
|
else
|
|
setItem(line, DESCRIPTION, new QTableWidgetItem(description));
|
|
item = new QTableWidgetItem();
|
|
setItem(line, OP_DATE, new QTableWidgetItem(v.sprintf("%02d/%02d/%d", op.day+1, month+1, year)));
|
|
if (op.amount < 0)
|
|
{
|
|
setItem(line, DEBIT, new QTableWidgetItem(v.sprintf("%.2lf", -op.amount)));
|
|
}
|
|
else
|
|
setItem(line, CREDIT, new QTableWidgetItem(v.sprintf("%.2lf", op.amount)));
|
|
|
|
if (!op.meta)
|
|
setItem(line, ACCOUNT, new QTableWidgetItem(user->GetAccountName(op.account)));
|
|
if (!fix && !op.meta)
|
|
setItem(line, CATEGORY, new QTableWidgetItem(_(cat.name.toStdString().c_str())));
|
|
|
|
checkBox = new QCheckBox();
|
|
checkBox->setCheckState(Qt::Unchecked);
|
|
setCellWidget(line, OP_DELETE, checkBox);
|
|
_deleteSignalMapper.setMapping(checkBox, op.id);
|
|
connect(checkBox, SIGNAL(stateChanged(int)), &_deleteSignalMapper, SLOT(map()));
|
|
|
|
checkBox = new QCheckBox();
|
|
checkBox->setCheckState((op.checked) ? Qt::Checked : Qt::Unchecked);
|
|
setCellWidget(line, CHECKED, checkBox);
|
|
_checkSignalMapper.setMapping(checkBox, op.id);
|
|
connect(checkBox, SIGNAL(stateChanged(int)), &_checkSignalMapper, SLOT(map()));
|
|
|
|
if (op.meta && !op.amount)
|
|
{
|
|
amount = _kiss->MetaPositiveAmount(op.id);
|
|
|
|
setItem(line, DEBIT, new QTableWidgetItem(v.sprintf("%.2lf", amount)));
|
|
setItem(line, CREDIT, new QTableWidgetItem(v.sprintf("%.2lf", amount)));
|
|
}
|
|
|
|
if (op.category)
|
|
color = cat.backcolor;
|
|
else
|
|
color = view::OWN_GREEN;
|
|
|
|
if (op.checked)
|
|
{
|
|
r = ((color.red()*1.5) >= 0xFF) ? 0xFF : color.red()*1.5 ;
|
|
g = ((color.green()*1.5) >= 0xFF) ? 0xFF : color.green()*1.5 ;
|
|
b = ((color.blue()*1.5) >= 0xFF) ? 0xFF : color.blue()*1.5 ;
|
|
color.setRgb(r, g, b, color.alpha());
|
|
}
|
|
|
|
SET_ROW_COLOR(line, color, cat.forecolor);
|
|
SET_ROW_FONT(line, user->GetCategoryFont(cat.id));
|
|
|
|
if (!_loadOperations)
|
|
{
|
|
if (op.meta)
|
|
resizeColumnToContents(TREE);
|
|
resizeColumnToContents(CATEGORY);
|
|
resizeColumnToContents(ACCOUNT);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
item = new QTableWidgetItem("");
|
|
setItem(line, DESCRIPTION, item);
|
|
if (fix)
|
|
{
|
|
SET_ROW_COLOR(line, view::OWN_YELLOW, Qt::black);
|
|
}
|
|
else
|
|
{
|
|
setItem(line, OP_DATE, new QTableWidgetItem(v.sprintf("%02d/%02d/%d", curDate.day(), month+1, year)));
|
|
SET_ROW_COLOR(line, view::OWN_GREEN, Qt::black);
|
|
}
|
|
|
|
SET_READ_ONLY(this->item(line, CHECKED));
|
|
SET_READ_ONLY(this->item(line, OP_DELETE));
|
|
SET_ROW_FONT(line, user->GetCategoryFont(0));
|
|
}
|
|
|
|
this->item(line, OP_DATE)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
|
|
this->item(line, DEBIT)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
|
|
this->item(line, CREDIT)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
|
|
this->item(line, OP_DELETE)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
|
|
this->item(line, CHECKED)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
|
|
|
|
if (op.id && op.meta)
|
|
{
|
|
int height = rowHeight(TREE);
|
|
QPushButton* button = new QPushButton("+");
|
|
_treeSignalMapper.setMapping(button, op.id);
|
|
connect(button, SIGNAL(clicked()), &_treeSignalMapper, SLOT(map()));
|
|
|
|
button->setMaximumSize(QSize(height, height));
|
|
setCellWidget(line, TREE, button);
|
|
|
|
SET_READ_ONLY(this->item(line, OP_DATE));
|
|
SET_READ_ONLY(this->item(line, CREDIT));
|
|
SET_READ_ONLY(this->item(line, DEBIT));
|
|
SET_READ_ONLY(this->item(line, CATEGORY));
|
|
SET_READ_ONLY(this->item(line, ACCOUNT));
|
|
}
|
|
else
|
|
SET_READ_ONLY(this->item(line, TREE));
|
|
|
|
resizeRowToContents(line);
|
|
|
|
layout();
|
|
|
|
_inModification = false;
|
|
}
|
|
|
|
void GridAccount::DeleteOperation(const Operation& op)
|
|
{
|
|
std::vector<Operation>::iterator it = std::find(_operations->begin(), _operations->end(), op.id);
|
|
|
|
if (it != _operations->end()) _operations->erase(it);
|
|
}
|
|
|
|
void GridAccount::InsertIntoGrid(Operation& op)
|
|
{
|
|
int i, a, start;
|
|
User* user = _kiss->GetUser();
|
|
Operation parent;
|
|
|
|
if (op.parent)
|
|
parent = GetOperation(op.parent);
|
|
|
|
// No previous fix operations
|
|
if (op.fix_cost && !_displayedOperations[1].id)
|
|
i = 1;
|
|
else
|
|
{
|
|
if (op.parent)
|
|
start = GetDisplayedRow(op.parent);
|
|
else
|
|
start = 0;
|
|
|
|
for(i=start; i<(int)_displayedOperations.size(); i++)
|
|
{
|
|
if (!_displayedOperations[i].id) continue;
|
|
if (_displayedOperations[i].parent) continue;
|
|
if ((_displayedOperations)[i].fix_cost && !op.fix_cost) continue;
|
|
if (!(_displayedOperations)[i].fix_cost && op.fix_cost) break;
|
|
if (user->_preferences["operation_order"] == "ASC")
|
|
{
|
|
if ((_displayedOperations)[i].day > op.day)
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if ((_displayedOperations)[i].day < op.day)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (op.parent)
|
|
{
|
|
if ((i-start) > (int)(parent.childs.size()))
|
|
i = start + parent.childs.size();
|
|
if (parent.day >= op.day)
|
|
i = start + 1;
|
|
}
|
|
else if (i == (int)_displayedOperations.size() ||
|
|
i == _fixCosts)
|
|
i--;
|
|
else if (!(_displayedOperations)[i].fix_cost && op.fix_cost)
|
|
i --;
|
|
}
|
|
|
|
for (a=0; a<(int)_operations->size(); a++)
|
|
{
|
|
if ((*_operations)[a].fix_cost && !op.fix_cost) continue;
|
|
if (!(*_operations)[a].fix_cost && op.fix_cost)
|
|
{
|
|
a--;
|
|
break;
|
|
}
|
|
if ((*_operations)[a].day > op.day)
|
|
{
|
|
a--;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (a < 0) a = 0;
|
|
_operations->insert(_operations->begin()+a, op);
|
|
|
|
InsertOperationWithWeek(user, (*_operations)[a], i, op.fix_cost, _curMonth, _curYear);
|
|
}
|
|
|
|
int GridAccount::RemoveMeta(Operation op, int line, bool removeRoot, bool deleteOp)
|
|
{
|
|
std::vector<Operation*>::iterator it, it2;
|
|
int i, deletedOperations = 0;
|
|
Operation op2;
|
|
QPushButton* button = qobject_cast<QPushButton*> (cellWidget(line, TREE));
|
|
|
|
for(i=0; i<(int)op.childs.size(); i++)
|
|
{
|
|
op2 = GetOperation(op.childs[i]);
|
|
if (op2.meta)
|
|
RemoveMeta(op2, line+1, true, deleteOp);
|
|
else
|
|
{
|
|
if (button->text() == "-")
|
|
{
|
|
removeRow(line+1);
|
|
deletedOperations++;
|
|
if (op2.fix_cost) _fixCosts--;
|
|
_displayedOperations.erase(_displayedOperations.begin()+line+1);
|
|
}
|
|
|
|
if (deleteOp)
|
|
{
|
|
DeleteOperation(op2);
|
|
if (_databaseSynchronization)
|
|
_kiss->DeleteOperation(op2);
|
|
}
|
|
}
|
|
}
|
|
|
|
op.childs.clear();
|
|
|
|
if (removeRoot)
|
|
{
|
|
button->disconnect(&_treeSignalMapper, SLOT(map()));
|
|
QCheckBox* checkBox = qobject_cast<QCheckBox*> (cellWidget(line, CHECKED));
|
|
checkBox->disconnect(&_checkSignalMapper, SLOT(map()));
|
|
checkBox = qobject_cast<QCheckBox*> (cellWidget(line, OP_DELETE));
|
|
checkBox->disconnect(&_deleteSignalMapper, SLOT(map()));
|
|
removeRow(line);
|
|
_displayedOperations.erase(_displayedOperations.begin()+line);
|
|
if (op.fix_cost) _fixCosts--;
|
|
if (deleteOp)
|
|
{
|
|
DeleteOperation(op);
|
|
if (_databaseSynchronization)
|
|
_kiss->DeleteOperation(op);
|
|
}
|
|
deletedOperations++;
|
|
}
|
|
|
|
return deletedOperations;
|
|
}
|
|
|
|
void GridAccount::CheckMeta(Operation& op, int line, bool check)
|
|
{
|
|
int i, new_line;
|
|
Operation op2;
|
|
QColor color ;
|
|
unsigned char r, g, b;
|
|
User* user = _kiss->GetUser();
|
|
|
|
QPushButton* button = qobject_cast<QPushButton*>(cellWidget(line, TREE));
|
|
|
|
for(i=0; i<(int)op.childs.size(); i++)
|
|
{
|
|
op2 = GetOperation(op.childs[i]);
|
|
op2.checked = check;
|
|
UpdateOperation(op2);
|
|
|
|
if (op2.meta)
|
|
CheckMeta(op2, line+1, check);
|
|
|
|
if (button->text() == "-")
|
|
{
|
|
QCheckBox* checkBox = qobject_cast<QCheckBox*>(cellWidget(line+i+1, CHECKED));
|
|
checkBox->setCheckState(check ? Qt::Checked : Qt::Unchecked);
|
|
color = user->GetCategory(op2.category).backcolor;
|
|
|
|
if (check)
|
|
{
|
|
r = ((color.red()*1.5) >= 0xFF) ? 0xFF : color.red()*1.5 ;
|
|
g = ((color.green()*1.5) >= 0xFF) ? 0xFF : color.green()*1.5 ;
|
|
b = ((color.blue()*1.5) >= 0xFF) ? 0xFF : color.blue()*1.5 ;
|
|
color.setRgb(r, g, b);
|
|
}
|
|
|
|
new_line = line+i+1;
|
|
SET_ROW_COLOR(new_line, color, user->GetCategory(op2.category).forecolor);
|
|
}
|
|
}
|
|
}
|
|
|
|
void GridAccount::OnMetaClicked(int id)
|
|
{
|
|
QPushButton* button = qobject_cast<QPushButton*> (_treeSignalMapper.mapping(id));
|
|
std::vector<Operation>::iterator it;
|
|
std::vector<int>::iterator it2;
|
|
int i, row;
|
|
Operation op, op2;
|
|
User* user = _kiss->GetUser();
|
|
|
|
it = std::find(_displayedOperations.begin(), _displayedOperations.end(), id);
|
|
|
|
if (it == _displayedOperations.end()) return ;
|
|
|
|
op = *it;
|
|
|
|
row = it - _displayedOperations.begin();
|
|
|
|
if (button->text() == "+")
|
|
{
|
|
for (i=1, it2=op.childs.begin(); it2!=op.childs.end(); it2++, i++)
|
|
{
|
|
op2 = GetOperation(*it2);
|
|
InsertOperationWithWeek(user, op2, row+i, op2.fix_cost, op2.month, op2.year);
|
|
}
|
|
button->setText("-");
|
|
}
|
|
else
|
|
{
|
|
RemoveMeta(op, row, false, false);
|
|
button->setText("+");
|
|
}
|
|
}
|
|
|
|
void GridAccount::OnCheckClicked(int id)
|
|
{
|
|
std::vector<Operation>::iterator it;
|
|
int row;
|
|
Operation op2;
|
|
QColor color;
|
|
User* user = _kiss->GetUser();
|
|
unsigned char r, g, b;
|
|
|
|
if (_inModification || _loadOperations) return;
|
|
|
|
QCheckBox* checkBox = qobject_cast<QCheckBox*> (_checkSignalMapper.mapping(id));
|
|
|
|
it = std::find(_displayedOperations.begin(), _displayedOperations.end(), id);
|
|
|
|
if (it == _displayedOperations.end()) return ;
|
|
|
|
_inModification = true;
|
|
|
|
row = it-_displayedOperations.begin();
|
|
_displayedOperations[row].checked = (checkBox->checkState() == Qt::Checked);
|
|
|
|
color = user->GetCategory(it->category).backcolor;
|
|
|
|
if (it->checked)
|
|
{
|
|
r = ((color.red()*1.5) >= 0xFF) ? 0xFF : color.red()*1.5 ;
|
|
g = ((color.green()*1.5) >= 0xFF) ? 0xFF : color.green()*1.5 ;
|
|
b = ((color.blue()*1.5) >= 0xFF) ? 0xFF : color.blue()*1.5 ;
|
|
color.setRgb(r, g, b);
|
|
}
|
|
|
|
SET_ROW_COLOR(row, color, user->GetCategory(it->category).forecolor);
|
|
SET_ROW_FONT(row, user->GetCategoryFont(it->category));
|
|
|
|
UpdateOperation(*it);
|
|
if (it->meta)
|
|
CheckMeta(*it, row, it->checked);
|
|
else
|
|
{
|
|
if (it->parent)
|
|
{
|
|
op2 = GetOperation(it->parent);
|
|
UpdateMeta(op2);
|
|
int row2 = GetDisplayedRow(op2.id);
|
|
QCheckBox* checkBox = qobject_cast<QCheckBox*>(cellWidget(row2, CHECKED));
|
|
checkBox->setCheckState(op2.checked ? Qt::Checked : Qt::Unchecked);
|
|
|
|
color = user->GetCategory(op2.category).backcolor;
|
|
|
|
if (op2.checked)
|
|
{
|
|
r = ((color.red()*1.5) >= 0xFF) ? 0xFF : color.red()*1.5 ;
|
|
g = ((color.green()*1.5) >= 0xFF) ? 0xFF : color.green()*1.5 ;
|
|
b = ((color.blue()*1.5) >= 0xFF) ? 0xFF : color.blue()*1.5 ;
|
|
color.setRgb(r, g, b);
|
|
}
|
|
|
|
SET_ROW_COLOR(row2, color, user->GetCategory(op2.category).forecolor);
|
|
}
|
|
}
|
|
|
|
_inModification = false;
|
|
_kiss->UpdateStats();
|
|
}
|
|
|
|
void GridAccount::OnDeleteClicked(int id)
|
|
{
|
|
std::vector<Operation>::iterator it;
|
|
std::vector<int>::iterator it2;
|
|
int row;
|
|
User* user = _kiss->GetUser();
|
|
Operation op, op_tmp, op_tmp2;
|
|
QColor color;
|
|
unsigned char r, g, b;
|
|
|
|
if (_inModification || _loadOperations) return;
|
|
|
|
QCheckBox* checkBox = qobject_cast<QCheckBox*> (_deleteSignalMapper.mapping(id));
|
|
|
|
if (checkBox->checkState() == Qt::Unchecked) return;
|
|
|
|
it = std::find(_displayedOperations.begin(), _displayedOperations.end(), id);
|
|
|
|
if (it == _displayedOperations.end()) return ;
|
|
|
|
if (QMessageBox::question(0, "KissCount", _("Are you sure want to delete : \n")+it->description, QMessageBox::Yes|QMessageBox::No) == QMessageBox::No)
|
|
{
|
|
checkBox->setCheckState(Qt::Unchecked);
|
|
return;
|
|
}
|
|
|
|
op = *it; // Make a copy
|
|
|
|
_inModification = true;
|
|
|
|
row = it-_displayedOperations.begin();
|
|
|
|
if (op.parent)
|
|
user->UnGroup(_displayedOperations[row]);
|
|
|
|
if (op.meta)
|
|
RemoveMeta(_displayedOperations[row], row, true, true);
|
|
else
|
|
{
|
|
if (op.parent)
|
|
{
|
|
op_tmp = GetOperation(op.parent);
|
|
it2 = std::find(op_tmp.childs.begin(), op_tmp.childs.end(), op.id);
|
|
if (it2 != op_tmp.childs.end())
|
|
op_tmp.childs.erase(it2);
|
|
}
|
|
|
|
removeRow(row);
|
|
DeleteOperation(*it);
|
|
if (_databaseSynchronization)
|
|
_kiss->DeleteOperation(*it);
|
|
_displayedOperations.erase(_displayedOperations.begin()+row);
|
|
|
|
if (op.parent)
|
|
{
|
|
if (op_tmp.childs.size() < 2)
|
|
{
|
|
if (op_tmp.childs.size() == 1)
|
|
{
|
|
op_tmp2 = GetOperation(op_tmp.childs[0]);
|
|
op_tmp2.parent = 0;
|
|
UpdateOperation(op_tmp2);
|
|
row = GetDisplayedRow(op_tmp2.id);
|
|
_displayedOperations[row] = op_tmp2;
|
|
}
|
|
|
|
row = GetDisplayedRow(op.parent);
|
|
removeRow(row);
|
|
DeleteOperation(op_tmp);
|
|
if (_databaseSynchronization)
|
|
_kiss->DeleteOperation(op_tmp);
|
|
_displayedOperations.erase(_displayedOperations.begin()+row);
|
|
if (op.fix_cost)
|
|
_fixCosts--;
|
|
setItem(row, DESCRIPTION, new QTableWidgetItem(op.description)); // Remove tabulation
|
|
color = user->GetCategory(op.category).backcolor;
|
|
|
|
if (op.checked)
|
|
{
|
|
r = ((color.red()*1.5) >= 0xFF) ? 0xFF : color.red()*1.5 ;
|
|
g = ((color.green()*1.5) >= 0xFF) ? 0xFF : color.green()*1.5 ;
|
|
b = ((color.blue()*1.5) >= 0xFF) ? 0xFF : color.blue()*1.5 ;
|
|
color.setRgb(r, g, b);
|
|
}
|
|
|
|
SET_ROW_COLOR(row, color, user->GetCategory(op.category).forecolor);
|
|
SET_ROW_FONT(row, user->GetCategoryFont(op.category));
|
|
}
|
|
else
|
|
{
|
|
UpdateMeta(op_tmp);
|
|
row = GetDisplayedRow(op_tmp.id);
|
|
RemoveMeta(op_tmp, row, true, false);
|
|
InsertIntoGrid(op_tmp);
|
|
}
|
|
}
|
|
if (op.fix_cost)
|
|
_fixCosts--;
|
|
ComputeWeeks();
|
|
}
|
|
|
|
_kiss->UpdateStats();
|
|
_inModification = false;
|
|
}
|
|
|
|
void GridAccount::OnOperationModified(int row, int col)
|
|
{
|
|
User* user = _kiss->GetUser();
|
|
Operation new_op, cur_op, op_tmp, op_tmp2;
|
|
int op_complete = 6, i, last_day;
|
|
QString value, v ;
|
|
QDate date;
|
|
bool need_insertion = false;
|
|
QColor color ;
|
|
unsigned char r, g, b;
|
|
std::vector<int>::iterator it;
|
|
Operation op, op2;
|
|
double amount;
|
|
QFont font;
|
|
Category cat ;
|
|
bool fix_cost;
|
|
QDate curDate = QDate::currentDate();
|
|
|
|
// Avoid recursives calls
|
|
if (_inModification || _loadOperations) return;
|
|
|
|
_inModification = true ;
|
|
|
|
cur_op = (_displayedOperations)[row] ;
|
|
|
|
new_op.id = 0;
|
|
new_op.parent = 0;
|
|
new_op.day = 0;
|
|
new_op.month = 0;
|
|
new_op.year = 0;
|
|
new_op.amount = 0.0;
|
|
new_op.description = "";
|
|
new_op.category = 0;
|
|
new_op.fix_cost = false;
|
|
new_op.account = 0;
|
|
new_op.checked = 0;
|
|
new_op.transfert = 0;
|
|
new_op.formula = "";
|
|
new_op.meta = false;
|
|
new_op._virtual = false;
|
|
|
|
if (col == DEBIT)
|
|
setItem(row, CREDIT, new QTableWidgetItem(""));
|
|
else if (col == CREDIT)
|
|
setItem(row, DEBIT, new QTableWidgetItem(""));
|
|
|
|
value = item(row, DESCRIPTION)->text();
|
|
if (value.length())
|
|
{
|
|
new_op.description = value.trimmed();
|
|
op_complete--;
|
|
}
|
|
|
|
value = item(row, OP_DATE)->text();
|
|
if (value.length())
|
|
{
|
|
date = QDate::fromString(value, "dd/MM/yyyy");
|
|
new_op.day = date.day()-1;
|
|
new_op.month = date.month()-1;
|
|
new_op.year = date.year();
|
|
op_complete--;
|
|
}
|
|
|
|
if (!cur_op.meta && col == DESCRIPTION &&
|
|
(!item(row, CATEGORY)->text().length() ||
|
|
!item(row, ACCOUNT)->text().length()))
|
|
{
|
|
new_op.fix_cost = (row <= _fixCosts);
|
|
if (_kiss->SearchPreviousOperation(&op_tmp, new_op, _curMonth, _curYear, _canAddOperation))
|
|
{
|
|
if (!item(row, CATEGORY)->text().length())
|
|
setItem(row, CATEGORY, new QTableWidgetItem(_(user->GetCategoryName(op_tmp.category).toStdString().c_str())));
|
|
|
|
if (!item(row, ACCOUNT)->text().length())
|
|
setItem(row, ACCOUNT, new QTableWidgetItem(user->GetAccountName(op_tmp.account)));
|
|
|
|
col = CATEGORY;
|
|
new_op.fix_cost = (new_op.category == user->GetCategoryId("Fix"));
|
|
}
|
|
}
|
|
|
|
value = item(row, DEBIT)->text();
|
|
if (value.length())
|
|
{
|
|
new_op.amount = value.toDouble();
|
|
if (new_op.amount < 0)
|
|
{
|
|
new_op.amount *= -1.0;
|
|
setItem(row, DEBIT, new QTableWidgetItem(value.sprintf("%.2lf", new_op.amount)));
|
|
}
|
|
if (new_op.amount != 0.0) new_op.amount *= -1.0;
|
|
op_complete--;
|
|
new_op.formula = _displayedOperations[row].formula;
|
|
}
|
|
|
|
value = item(row, CREDIT)->text();
|
|
if (value.length())
|
|
{
|
|
new_op.amount = value.toDouble();
|
|
if (new_op.amount < 0)
|
|
{
|
|
new_op.amount *= -1.0;
|
|
setItem(row, DEBIT, new QTableWidgetItem(value.sprintf("%.2lf", new_op.amount)));
|
|
}
|
|
op_complete--;
|
|
new_op.formula = _displayedOperations[row].formula;
|
|
}
|
|
|
|
value = item(row, CATEGORY)->text();
|
|
if (value.length())
|
|
{
|
|
new_op.category = user->GetCategoryId(value);
|
|
op_complete--;
|
|
}
|
|
|
|
value = item(row, ACCOUNT)->text();
|
|
if (value.length())
|
|
{
|
|
new_op.account = user->GetAccountId(value);
|
|
op_complete--;
|
|
}
|
|
|
|
if (cellWidget(row, CHECKED))
|
|
new_op.checked = _displayedOperations[row].checked;
|
|
else
|
|
new_op.checked = false;
|
|
op_complete--;
|
|
|
|
color = user->GetCategory(new_op.category).backcolor;
|
|
|
|
if (new_op.checked)
|
|
{
|
|
r = ((color.red()*1.5) >= 0xFF) ? 0xFF : color.red()*1.5 ;
|
|
g = ((color.green()*1.5) >= 0xFF) ? 0xFF : color.green()*1.5 ;
|
|
b = ((color.blue()*1.5) >= 0xFF) ? 0xFF : color.blue()*1.5 ;
|
|
color.setRgb(r, g, b);
|
|
}
|
|
|
|
SET_ROW_COLOR(row, color, user->GetCategory(new_op.category).forecolor);
|
|
SET_ROW_FONT(row, user->GetCategoryFont(new_op.category));
|
|
|
|
fix_cost = (row <= _fixCosts);
|
|
|
|
// Modify an operation
|
|
if (!_canAddOperation || (row < _fixCosts ||
|
|
(row > _fixCosts &&
|
|
row < (int)(_displayedOperations.size()-1))))
|
|
{
|
|
new_op.id = cur_op.id;
|
|
new_op.fix_cost = fix_cost;
|
|
new_op.transfert = cur_op.transfert;
|
|
new_op.meta = cur_op.meta;
|
|
new_op.parent = cur_op.parent;
|
|
new_op.childs = cur_op.childs;
|
|
new_op._virtual = cur_op._virtual;
|
|
|
|
if (cur_op.day != new_op.day)
|
|
{
|
|
need_insertion = true;
|
|
removeRow(row);
|
|
DeleteOperation(cur_op);
|
|
_displayedOperations.erase(_displayedOperations.begin()+row);
|
|
if (fix_cost)
|
|
_fixCosts--;
|
|
}
|
|
else
|
|
(_displayedOperations)[row] = new_op;
|
|
|
|
UpdateOperation(new_op);
|
|
}
|
|
// Add an operation
|
|
else
|
|
{
|
|
if (op_complete) {
|
|
_inModification = false ;
|
|
return ;
|
|
}
|
|
need_insertion = true;
|
|
new_op.fix_cost = fix_cost;
|
|
new_op.meta = false;
|
|
new_op._virtual = false;
|
|
new_op.parent = 0;
|
|
|
|
for(i=0; i<NUMBER_COLS_OPS; i++)
|
|
{
|
|
if (fix_cost && i == CATEGORY) continue;
|
|
setItem(row, i, new QTableWidgetItem(""));
|
|
}
|
|
if (!fix_cost)
|
|
{
|
|
if (_curMonth+1 == curDate.month() &&
|
|
_curYear == curDate.year())
|
|
setItem(row, OP_DATE, new QTableWidgetItem(v.sprintf("%02d/%02d/%d", curDate.day(), _curMonth+1, _curYear)));
|
|
}
|
|
DEFAULT_FONT(font);
|
|
|
|
if (fix_cost)
|
|
{
|
|
SET_ROW_COLOR(row, view::OWN_YELLOW, Qt::black);
|
|
}
|
|
else
|
|
{
|
|
SET_ROW_COLOR(row, view::OWN_GREEN, Qt::black);
|
|
}
|
|
|
|
SET_ROW_FONT(row, font);
|
|
|
|
new_op.id = _kiss->AddOperation(new_op);
|
|
}
|
|
|
|
if (!new_op.meta && user->GetAccount(new_op.account).blocked && new_op.amount < 0)
|
|
QMessageBox::warning(0, _("Warning"), _("You made a debit on a blocked account"));
|
|
|
|
if (need_insertion)
|
|
InsertIntoGrid(new_op);
|
|
|
|
if (new_op.parent)
|
|
{
|
|
row = GetDisplayedRow(new_op.parent);
|
|
|
|
last_day = new_op.day;
|
|
new_op = _displayedOperations[row];
|
|
|
|
it = std::find(new_op.childs.begin(), new_op.childs.end(), cur_op.id);
|
|
new_op.childs.erase(it);
|
|
|
|
i = 0;
|
|
for(it = new_op.childs.begin(); it != new_op.childs.end(); it++)
|
|
{
|
|
op2 = GetOperation(*it);
|
|
if ((int)op2.day > last_day) break;
|
|
i++;
|
|
}
|
|
|
|
new_op.childs.insert(new_op.childs.begin()+i, cur_op.id);
|
|
|
|
last_day = new_op.day;
|
|
|
|
UpdateMeta(new_op);
|
|
|
|
_displayedOperations[row] = new_op;
|
|
|
|
cat = user->GetCategory(new_op.category);
|
|
|
|
if (new_op.category)
|
|
color = cat.backcolor;
|
|
else
|
|
color = view::OWN_GREEN;
|
|
|
|
QCheckBox* checkBox = qobject_cast<QCheckBox*> (_checkSignalMapper.mapping(new_op.id));
|
|
if (new_op.checked)
|
|
{
|
|
r = ((color.red()*1.5) >= 0xFF) ? 0xFF : color.red()*1.5 ;
|
|
g = ((color.green()*1.5) >= 0xFF) ? 0xFF : color.green()*1.5 ;
|
|
b = ((color.blue()*1.5) >= 0xFF) ? 0xFF : color.blue()*1.5 ;
|
|
color.setRgb(r, g, b);
|
|
checkBox->setCheckState(Qt::Checked);
|
|
}
|
|
else
|
|
checkBox->setCheckState(Qt::Unchecked);
|
|
|
|
setItem(row, OP_DATE, new QTableWidgetItem(v.sprintf("%02d/%02d/%d", new_op.day+1, _curMonth+1, _curYear)));
|
|
|
|
if (!_displayedOperations[row].amount)
|
|
{
|
|
amount = _kiss->MetaPositiveAmount(new_op.id);
|
|
|
|
setItem(row, DEBIT, new QTableWidgetItem(v.sprintf("%.2lf", amount)));
|
|
setItem(row, CREDIT, new QTableWidgetItem(v.sprintf("%.2lf", amount)));
|
|
}
|
|
else
|
|
{
|
|
if (_displayedOperations[row].amount < 0)
|
|
{
|
|
setItem(row, DEBIT, new QTableWidgetItem(v.sprintf("%.2lf", -new_op.amount)));
|
|
setItem(row, CREDIT, new QTableWidgetItem(""));
|
|
}
|
|
else
|
|
{
|
|
setItem(row, DEBIT, new QTableWidgetItem(""));
|
|
setItem(row, CREDIT, new QTableWidgetItem(v.sprintf("%.2lf", new_op.amount)));
|
|
}
|
|
}
|
|
|
|
this->item(row, OP_DATE)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
|
|
this->item(row, DEBIT)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
|
|
this->item(row, CREDIT)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
|
|
|
|
SET_ROW_COLOR(row, color, cat.forecolor);
|
|
|
|
if (new_op.category && cat.font.length())
|
|
{
|
|
SET_ROW_FONT(row, user->GetCategoryFont(cat.id));
|
|
}
|
|
|
|
// Move updated meta
|
|
if ((int)new_op.day != last_day)
|
|
{
|
|
int i;
|
|
RemoveMeta(new_op, row, true, false);
|
|
InsertIntoGrid(new_op);
|
|
row = GetDisplayedRow(new_op.id);
|
|
for (i=1, it=new_op.childs.begin(); it!=new_op.childs.end(); it++, i++)
|
|
{
|
|
op2 = GetOperation(*it);
|
|
InsertOperationWithWeek(user, op2, row+i, op2.fix_cost, _curMonth, _curYear);
|
|
}
|
|
QPushButton* button = qobject_cast<QPushButton*> (cellWidget(row, TREE));
|
|
if (button->text() == "+")
|
|
button->setText("-");
|
|
else
|
|
button->setText("+");
|
|
}
|
|
}
|
|
|
|
_kiss->UpdateStats();
|
|
_inModification = false ;
|
|
}
|
|
|
|
void GridAccount::UpdateMeta(Operation& meta)
|
|
{
|
|
std::vector<int>::iterator it;
|
|
Operation op ;
|
|
int category = 0;
|
|
bool updateCat = false ;
|
|
|
|
if (!meta.childs.size()) return ;
|
|
|
|
meta.category = 0;
|
|
meta.checked = true;
|
|
meta.amount = 0;
|
|
|
|
op = GetOperation(meta.childs[0]);
|
|
meta.year = op.year;
|
|
meta.month = op.month;
|
|
meta.day = op.day;
|
|
|
|
for(it=meta.childs.begin(); it!=meta.childs.end(); it++)
|
|
{
|
|
op = GetOperation(*it);
|
|
if (op.year <= meta.year && op.month <= meta.month && op.day < meta.day)
|
|
{
|
|
meta.year = op.year;
|
|
meta.month = op.month;
|
|
meta.day = op.day;
|
|
}
|
|
meta.checked &= op.checked;
|
|
if (!meta.description.length() && op.description.length())
|
|
meta.description = op.description;
|
|
if (!category)
|
|
{
|
|
if (op.category)
|
|
{
|
|
category = op.category;
|
|
updateCat = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (op.category && op.category != category)
|
|
updateCat = false;
|
|
}
|
|
op.parent = meta.id;
|
|
}
|
|
|
|
if (updateCat)
|
|
meta.category = category;
|
|
|
|
meta.amount = _kiss->MetaAmount(meta.id);
|
|
|
|
if (_databaseSynchronization)
|
|
_kiss->UpdateOperation(meta);
|
|
}
|
|
|
|
void GridAccount::Group()
|
|
{
|
|
std::vector<int> rows;
|
|
std::vector<int>::iterator it;
|
|
std::vector<Operation> ops;
|
|
std::vector<Operation>::iterator it2;
|
|
std::vector<int>::iterator it3;
|
|
int parent = 0, deletedRows;
|
|
Operation op, op2;
|
|
int fix = -1, i, a, row;
|
|
|
|
QModelIndexList selected = selectedIndexes();
|
|
|
|
for (int i = 0; i < selected.size(); ++i)
|
|
{
|
|
row = selected[i].row();
|
|
op = _displayedOperations[row] ;
|
|
|
|
if (op.id)
|
|
{
|
|
if (!parent)
|
|
{
|
|
if (op.parent)
|
|
parent = op.parent;
|
|
else if(op.meta)
|
|
parent = op.id;
|
|
}
|
|
else
|
|
{
|
|
if ((parent && op.parent && op.parent != parent))
|
|
{
|
|
QMessageBox::critical(0, _("Error"), _("Cannot group these operations"));
|
|
return ;
|
|
}
|
|
}
|
|
|
|
if (op.parent)
|
|
{
|
|
row = GetDisplayedRow(op.parent);
|
|
op = _displayedOperations[row] ;
|
|
}
|
|
|
|
if (fix != -1 && ((!fix && op.fix_cost) || (fix && !op.fix_cost)))
|
|
{
|
|
QMessageBox::critical(0, _("Error"), _("Cannot group these operations"));
|
|
return ;
|
|
}
|
|
|
|
if (fix == -1)
|
|
fix = op.fix_cost ? 1 : 0;
|
|
|
|
ops.push_back(op);
|
|
rows.push_back(row);
|
|
}
|
|
}
|
|
|
|
if (!ops.size()) return;
|
|
|
|
if (!parent)
|
|
{
|
|
if (rows.size() < 2) return;
|
|
|
|
op.parent = 0;
|
|
op.day = ops[0].day;
|
|
op.month = ops[0].month;
|
|
op.year = ops[0].year;
|
|
op.amount = 0;
|
|
op.description = "";
|
|
op.category = 0;
|
|
op.fix_cost = fix;
|
|
op.account = 0;
|
|
op.checked = false;
|
|
op.transfert = 0;
|
|
op.formula = "";
|
|
op.meta = true;
|
|
op.childs.clear();
|
|
|
|
op.id = _kiss->AddOperation(op);
|
|
}
|
|
else
|
|
{
|
|
if (rows.size() < 1) return;
|
|
|
|
row = GetDisplayedRow(parent);
|
|
op = _displayedOperations[row];
|
|
|
|
//if (op.id) return;
|
|
}
|
|
|
|
for(i=0; i<(int)rows.size(); i++)
|
|
{
|
|
if (ops[i].meta)
|
|
deletedRows = RemoveMeta(ops[i], rows[i], true, false);
|
|
else
|
|
{
|
|
if (ops[i].fix_cost) _fixCosts--;
|
|
removeRow(rows[i]);
|
|
_displayedOperations.erase(_displayedOperations.begin()+rows[i]);
|
|
deletedRows = 1;
|
|
}
|
|
for(a=i+1; a<(int)rows.size(); a++)
|
|
if (rows[a] >= rows[i])
|
|
rows[a] -= deletedRows;
|
|
}
|
|
|
|
for(it2=ops.begin(); it2!=ops.end(); it2++)
|
|
{
|
|
if (it2->id == parent) continue;
|
|
|
|
for (i=0, it3=op.childs.begin(); it3!=op.childs.end(); it3++, i++)
|
|
{
|
|
op2 = GetOperation(*it3);
|
|
if (*it3 == it2->id ||
|
|
op2.day > it2->day)
|
|
break;
|
|
}
|
|
|
|
if (i) i--;
|
|
|
|
if (it3 == op.childs.end())
|
|
op.childs.push_back(it2->id);
|
|
else if (*it3 == it2->id)
|
|
continue;
|
|
else
|
|
op.childs.insert(op.childs.begin()+i, it2->id);
|
|
|
|
it2->parent = op.id;
|
|
UpdateOperation(*it2);
|
|
}
|
|
|
|
UpdateMeta(op);
|
|
|
|
InsertIntoGrid(op);
|
|
}
|
|
|
|
void GridAccount::GetSelectedOperations(std::vector<int>* rows)
|
|
{
|
|
Operation op;
|
|
|
|
rows->clear();
|
|
|
|
QModelIndexList selected = selectedIndexes();
|
|
|
|
for (int i = 0; i < selected.size(); ++i)
|
|
{
|
|
op = _displayedOperations[selected[i].row()] ;
|
|
|
|
if (op.id)
|
|
rows->push_back(selected[i].row());
|
|
}
|
|
}
|
|
|
|
void GridAccount::UnGroup()
|
|
{
|
|
std::vector<int> rows;
|
|
std::vector<int>::iterator it;
|
|
std::vector<Operation> ops;
|
|
std::vector<int> ops2;
|
|
std::vector<Operation>::iterator it2;
|
|
std::vector<int>::iterator it3;
|
|
int parent = 0;
|
|
Operation op, op2;
|
|
int fix = -1, i, a, line;
|
|
|
|
QModelIndexList selected = selectedIndexes();
|
|
|
|
for (int i = 0; i < selected.size(); ++i)
|
|
{
|
|
op = _displayedOperations[selected[i].row()] ;
|
|
|
|
if (op.id)
|
|
{
|
|
if ((parent && op.parent != parent)
|
|
|| (!op.parent && !op.meta))
|
|
{
|
|
QMessageBox::critical(0, _("Error"), _("Cannot ungroup these operations"));
|
|
return ;
|
|
}
|
|
|
|
if (fix != -1 && ((!fix && op.fix_cost) || (fix && !op.fix_cost)))
|
|
{
|
|
QMessageBox::critical(0, _("Error"), _("Cannot ungroup these operations"));
|
|
return ;
|
|
}
|
|
|
|
if (fix == -1)
|
|
fix = op.fix_cost ? 1 : 0;
|
|
|
|
if(op.meta)
|
|
{
|
|
parent = op.id;
|
|
continue;
|
|
}
|
|
|
|
if (!parent && op.parent)
|
|
parent = op.parent;
|
|
|
|
ops.push_back(op);
|
|
rows.push_back(selected[i].row());
|
|
}
|
|
}
|
|
|
|
if (!ops.size() && !parent) return;
|
|
|
|
removeLastGroup:
|
|
// Only one meta is selected
|
|
if (!ops.size())
|
|
{
|
|
line = GetDisplayedRow(parent);
|
|
op = _displayedOperations[line];
|
|
ops2 = op.childs;
|
|
RemoveMeta(op, line, true, false);
|
|
|
|
for(i=0; i<(int)ops2.size(); i++)
|
|
{
|
|
op2 = GetOperation(ops2[i]);
|
|
op2.parent = 0;
|
|
UpdateOperation(op2);
|
|
InsertIntoGrid(op2);
|
|
}
|
|
|
|
_kiss->DeleteOperation(op);
|
|
DeleteOperation(op);
|
|
}
|
|
else
|
|
{
|
|
if (!parent) return;
|
|
|
|
line = GetDisplayedRow(parent);
|
|
op2 = _displayedOperations[line];
|
|
|
|
for(i=0; i<(int)ops.size(); i++)
|
|
{
|
|
op = ops[i];
|
|
op.parent = 0;
|
|
UpdateOperation(op);
|
|
line = GetDisplayedRow(op.id);
|
|
removeRow(line);
|
|
_displayedOperations.erase(_displayedOperations.begin()+line);
|
|
InsertIntoGrid(GetOperation(op.id));
|
|
if (op.fix_cost) _fixCosts--;
|
|
for (a=0; a<(int)op2.childs.size(); a++)
|
|
if (op2.childs[a] == op.id)
|
|
{
|
|
op2.childs.erase(op2.childs.begin()+a);
|
|
break;
|
|
}
|
|
UpdateMeta(op2);
|
|
}
|
|
|
|
line = GetDisplayedRow(parent);
|
|
_displayedOperations[line] = op2;
|
|
|
|
if (op2.childs.size() < 2)
|
|
{
|
|
ops.clear();
|
|
// Sorry ...
|
|
goto removeLastGroup;
|
|
}
|
|
|
|
UpdateOperation(op2);
|
|
}
|
|
|
|
ComputeWeeks();
|
|
}
|
|
|
|
void GridAccount::MassUpdate(std::vector<int>& rows, bool do_childs, updateOperationFunc func, void** params)
|
|
{
|
|
int i, b;
|
|
std::vector<Operation>::iterator it;
|
|
Operation op, op2;
|
|
|
|
_parent->setEnabled(false);
|
|
|
|
_parent->setCursor(Qt::BusyCursor);
|
|
|
|
if (rows.size())
|
|
{
|
|
for(i=0; i<(int)rows.size(); i++)
|
|
{
|
|
op = _displayedOperations[rows[i]];
|
|
|
|
func (&op, params);
|
|
|
|
UpdateOperation(op);
|
|
|
|
if (op.meta && do_childs)
|
|
{
|
|
for(b=0; b<(int)op.childs.size(); b++)
|
|
{
|
|
op2 = GetOperation(op.childs[b]);
|
|
func (&op2, params);
|
|
UpdateOperation(op2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(it=_operations->begin(); it!=_operations->end(); it++)
|
|
{
|
|
func (&(*it), params);
|
|
if (_databaseSynchronization)
|
|
_kiss->UpdateOperation(*it);
|
|
|
|
if (it->meta && do_childs)
|
|
{
|
|
for(b=0; b<(int)it->childs.size(); b++)
|
|
{
|
|
op2 = GetOperation(it->childs[b]);
|
|
func (&op2, params);
|
|
UpdateOperation(op2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LoadOperations(_operations, 0, 0);
|
|
|
|
layout();
|
|
|
|
_parent->setEnabled(true);
|
|
|
|
_parent->setCursor(Qt::ArrowCursor);
|
|
}
|