diff --git a/src/view/AccountPanel.h b/src/view/AccountPanel.h index 7e2a150..09d0928 100644 --- a/src/view/AccountPanel.h +++ b/src/view/AccountPanel.h @@ -26,7 +26,7 @@ #include #include #include -#include "CalendarEditor.h" +#include "grid/CalendarEditor.h" #include "grid/wxGridCellBitmapRenderer.h" #include "view.h" diff --git a/src/view/SearchPanel.h b/src/view/SearchPanel.h index 82557b8..c643284 100644 --- a/src/view/SearchPanel.h +++ b/src/view/SearchPanel.h @@ -24,7 +24,7 @@ #include #include #include -#include "CalendarEditor.h" +#include "grid/CalendarEditor.h" #include "grid/wxGridCellBitmapRenderer.h" #include "AccountPanel.h" #include "grid/GridAccount.h" diff --git a/src/view/CalendarEditor.cpp b/src/view/grid/CalendarEditor.cpp similarity index 99% rename from src/view/CalendarEditor.cpp rename to src/view/grid/CalendarEditor.cpp index e66818e..a799e5e 100644 --- a/src/view/CalendarEditor.cpp +++ b/src/view/grid/CalendarEditor.cpp @@ -24,7 +24,7 @@ CalendarEditor::CalendarEditor(int day, int month, int year) : _day(day), _month wxDateTime date; int i; - _maxDay = date.GetLastMonthDay ((wxDateTime::Month) month, year).GetDay()+1; + _maxDay = date.GetLastMonthDay ((wxDateTime::Month) month, year).GetDay(); _days = new wxString[_maxDay]; diff --git a/src/view/CalendarEditor.h b/src/view/grid/CalendarEditor.h similarity index 100% rename from src/view/CalendarEditor.h rename to src/view/grid/CalendarEditor.h diff --git a/src/view/grid/GridAccount.cpp b/src/view/grid/GridAccount.cpp index ad4efb3..0c6e98b 100644 --- a/src/view/grid/GridAccount.cpp +++ b/src/view/grid/GridAccount.cpp @@ -143,7 +143,7 @@ void GridAccount::LoadOperations(std::vector* operations, bool canAdd _curYear = year; _displayedOperations.clear(); _displayedOperations.push_back(NULL); // Header - _fixCosts = 1; + _fixCosts = 0; it = _operations->begin(); @@ -188,9 +188,6 @@ void GridAccount::InsertOperationWithWeek(User* user, Operation* op, int line, b InsertOperation(user, op, line, fix, month, year); - if (fix) - _fixCosts++; - if (op && !fix) { for (it = _displayedOperations.begin(), curLine=0; @@ -222,7 +219,8 @@ void GridAccount::InsertOperationWithWeek(User* user, Operation* op, int line, b void GridAccount::InsertOperation(User* user, Operation* op, int line, bool fix, int month, int year) { std::vector::iterator it; - int r, g, b; + std::vector::iterator it2; + int r, g, b, amount; wxColour color; wxDateTime curDate; wxString description; @@ -241,7 +239,7 @@ void GridAccount::InsertOperation(User* user, Operation* op, int line, bool fix, if (op && op->meta) { - SetCellRenderer(line, TREE, new wxGridCellTreeButtonRenderer()); + SetCellRenderer(line, TREE, new wxGridCellTreeButtonRenderer(true)); SetCellEditor(line, TREE, new wxGridCellTreeButtonEditor()); SetReadOnly(line, DATE, true); @@ -264,6 +262,7 @@ void GridAccount::InsertOperation(User* user, Operation* op, int line, bool fix, { SetCellValue(line, CATEGORY, _("Fix")); SetReadOnly(line, CATEGORY); + _fixCosts++; } if (op) @@ -279,8 +278,9 @@ void GridAccount::InsertOperation(User* user, Operation* op, int line, bool fix, SetCellValue(line, DEBIT, wxString::Format(wxT("%.2lf"), -op->amount)); else SetCellValue(line, CREDIT, wxString::Format(wxT("%.2lf"), op->amount)); - SetCellValue(line, ACCOUNT, user->GetAccountName(op->account)); - if (!fix) + if (!op->meta) + SetCellValue(line, ACCOUNT, user->GetAccountName(op->account)); + if (!fix && !op->meta) SetCellValue(line, CATEGORY, cat.name); SetCellRenderer(line, DELETE, new wxGridCellBoolRenderer ()); SetCellEditor(line, DELETE, new wxGridCellBoolEditor ()); @@ -304,6 +304,19 @@ void GridAccount::InsertOperation(User* user, Operation* op, int line, bool fix, font = user->GetCategoryFont(cat.id); SET_ROW_FONT(line, font); } + + if (op->meta && !op->amount) + { + amount = 0; + for(it2=op->childs.begin(); it2!=op->childs.end(); it2++) + { + if ((*it2)->amount > 0) + amount += (*it2)->amount; + } + + SetCellValue(line, DEBIT, wxString::Format(wxT("%.2lf"), amount)); + SetCellValue(line, CREDIT, wxString::Format(wxT("%.2lf"), amount)); + } } else { @@ -385,6 +398,80 @@ void GridAccount::DeleteOperation(const Operation& op) } } +void GridAccount::InsertIntoGrid(Operation* op) +{ + int i; + User* user = _kiss->GetUser(); + + for(i=0; i<(int)_displayedOperations.size(); i++) + { + if (_displayedOperations[i] == NULL) continue; + if ((_displayedOperations)[i]->fix_cost && !op->fix_cost) continue; + if (!(_displayedOperations)[i]->fix_cost && op->fix_cost) break; + if (user->_preferences[wxT("operation_order")] == wxT("ASC")) + { + if ((_displayedOperations)[i]->day > op->day) + break; + + } + else + { + if ((_displayedOperations)[i]->day < op->day) + break; + } + } + + if (!(_displayedOperations)[i]->fix_cost && op->fix_cost) + i --; + else if (i == (int)_displayedOperations.size() || + i == _fixCosts) i--; + + _operations->push_back(*op); + + InsertOperationWithWeek(user, &((*_operations)[_operations->size()-1]), i, op->fix_cost, _curMonth, _curYear); +} + +void GridAccount::RemoveMeta(Operation* op, int line, bool removeRoot, bool deleteOp) +{ + std::vector::iterator it, it2; + wxGridCellTreeButtonRenderer* treeRenderer; + + treeRenderer = (wxGridCellTreeButtonRenderer*) GetCellRenderer(line, TREE); + + if (treeRenderer->IsCollapsed()) + { + for(it=op->childs.begin(); it!=op->childs.end(); it++) + { + if ((*it)->meta) + RemoveMeta(*it, line+1, true, deleteOp); + else + { + DeleteRows(line+1, 1); + _displayedOperations.erase(_displayedOperations.begin()+line+1); + if (deleteOp) + { + DeleteOperation(**it); + _kiss->DeleteOperation(**it); + } + } + + } + } + + if (removeRoot) + { + DeleteRows(line, 1); + _displayedOperations.erase(_displayedOperations.begin()+line); + if (deleteOp) + { + DeleteOperation(*op); + _kiss->DeleteOperation(*op); + } + } + + treeRenderer->DecRef(); +} + void GridAccount::OnOperationModified(wxGridEvent& event) { User* user = _kiss->GetUser(); @@ -398,11 +485,39 @@ void GridAccount::OnOperationModified(wxGridEvent& event) static bool inModification = false ; wxColour color ; unsigned char r, g, b; + wxGridCellTreeButtonRenderer* treeRenderer; + std::vector::iterator it; + Operation* op; // Avoid recursives calls if (inModification) return; inModification = true ; + + if (col == TREE) + { + treeRenderer = (wxGridCellTreeButtonRenderer*) GetCellRenderer(row, col); + + op = _displayedOperations[row]; + + // Invert not already applied + if (!treeRenderer->IsCollapsed()) + { + for (i=1, it=op->childs.begin(); it!=op->childs.end(); it++, i++) + { + InsertOperation(user, *it, row+i, (*it)->fix_cost, _curMonth, _curYear); + } + } + else + { + RemoveMeta(op, row, false, false); + } + + treeRenderer->DecRef(); + + inModification = false; + return; + } if (col == DEBIT) SetCellValue(row, CREDIT, wxT("")); @@ -510,10 +625,18 @@ void GridAccount::OnOperationModified(wxGridEvent& event) if (col == DELETE) { - DeleteRows(row, 1); - DeleteOperation(cur_op); - _kiss->DeleteOperation(cur_op); - _displayedOperations.erase(_displayedOperations.begin()+row); + if (cur_op.parent.Length()) + user->UnGroup(_displayedOperations[row]); + + if (cur_op.meta) + RemoveMeta(_displayedOperations[row], row, true, true); + else + { + DeleteRows(row, 1); + DeleteOperation(cur_op); + _kiss->DeleteOperation(cur_op); + _displayedOperations.erase(_displayedOperations.begin()+row); + } _fixCosts = _fixCosts--; inModification = false ; event.Skip(); @@ -523,6 +646,9 @@ void GridAccount::OnOperationModified(wxGridEvent& event) new_op.id = cur_op.id; new_op.fix_cost = true; new_op.transfert = cur_op.transfert; + new_op.meta = cur_op.meta; + new_op.parent = cur_op.parent; + new_op.childs = cur_op.childs; if (cur_op.day != new_op.day) { @@ -551,6 +677,7 @@ void GridAccount::OnOperationModified(wxGridEvent& event) need_insertion = true; fix_op = true; new_op.fix_cost = true; + new_op.meta = false; for(i=0; iAddOperation(new_op); @@ -572,13 +699,24 @@ void GridAccount::OnOperationModified(wxGridEvent& event) new_op.id = cur_op.id; new_op.fix_cost = false; new_op.transfert = cur_op.transfert; + new_op.meta = cur_op.meta; + new_op.parent = cur_op.parent; + new_op.childs = cur_op.childs; if (col == DELETE) { - DeleteRows(row, 1); - DeleteOperation(cur_op); - _displayedOperations.erase(_displayedOperations.begin()+row); - _kiss->DeleteOperation(cur_op); + if (cur_op.parent.Length()) + user->UnGroup(_displayedOperations[row]); + + if (cur_op.meta) + RemoveMeta(_displayedOperations[row], row, true, true); + else + { + DeleteRows(row, 1); + DeleteOperation(cur_op); + _displayedOperations.erase(_displayedOperations.begin()+row); + _kiss->DeleteOperation(cur_op); + } inModification = false ; event.Skip(); return ; @@ -608,6 +746,7 @@ void GridAccount::OnOperationModified(wxGridEvent& event) need_insertion = true; fix_op = false; new_op.fix_cost = false; + new_op.meta = false; for(i=0; ifix_cost && !fix_op) continue; - if (!(_displayedOperations)[i]->fix_cost && fix_op) break; - if (user->_preferences[wxT("operation_order")] == wxT("ASC")) - { - if ((_displayedOperations)[i]->day > new_op.day) - break; - - } - else - { - if ((_displayedOperations)[i]->day < new_op.day) - break; - } - } - - if (i == (int)_displayedOperations.size()) i--; - - _operations->push_back(new_op); - - InsertOperationWithWeek(user, &((*_operations)[_operations->size()-1]), i, fix_op, _curMonth, _curYear); - if (fix_op) - _fixCosts = _fixCosts+1; - } + InsertIntoGrid(&new_op); inModification = false ; event.Skip(); } +void GridAccount::UpdateMeta(Operation* op, std::vector ops) +{ + std::vector::iterator it; + Operation* op_ ; + wxString category = wxT(""); + bool updateCat = false ; + + op->category = wxT(""); + + for(it=ops.begin(); it!=ops.end(); it++) + { + op_ = *it; + if (op_->year <= op->year && op_->month <= op->month && op_->day < op->day) + { + op->year = op_->year; + op->month = op_->month; + op->day = op_->day; + } + op->amount += op_->amount; + if (!op->description.Length() && op_->description.Length()) + op->description = op_->description; + if (!category.Length()) + { + if (op_->category.Length()) + { + category = op_->category; + updateCat = true; + } + } + else + { + if (op_->category.Length() && op_->category != category) + updateCat = false; + } + } + + if (updateCat) + op->category = category; +} + void GridAccount::Group() { + std::vector rows; + std::vector::iterator it; + std::vector ops; + std::vector::iterator it2, it3; + wxString parent = wxT(""); + Operation* op; + int fix = -1, i; + // Singly selected cells. + const wxGridCellCoordsArray& cells(GetSelectedCells()); + for (size_t i = 0; i < cells.size(); ++i) + { + const wxGridCellCoords& c = cells[i]; + + for (it=rows.begin(); it!=rows.end(); it++) + if (*it == c.GetRow()) + break; + + if (it != rows.end()) continue; + + op = _displayedOperations[c.GetRow()] ; + + if (op) + { + if (!parent.Length()) + { + if (op->parent.Length()) + parent = op->parent; + else if(op->meta) + parent = op->id; + } + else + { + if ((parent.Length() && op->parent != parent) || (fix != -1 && ((!fix && op->fix_cost) || (fix && !op->fix_cost)))) + { + wxMessageBox(_("Cannot group these operations"), _("Error"), wxICON_ERROR | wxOK); + return ; + } + } + + if (fix == -1) + fix = op->fix_cost ? 1 : 0; + + rows.push_back(c.GetRow()); + ops.push_back(op); + } + } + + if (rows.size() < 2) return; + + if (!parent.Length()) + { + op = new Operation; + op->parent = wxT(""); + op->day = ops[0]->day; + op->month = ops[0]->month; + op->year = ops[0]->year; + op->amount = 0; + op->description = wxT(""); + op->category = wxT(""); + op->fix_cost = fix; + op->account = wxT(""); + op->checked = false; + op->transfert = wxT(""); + op->formula = wxT(""); + op->meta = true; + + op->id = _kiss->AddOperation(*op); + } + else + { + for(i=0, it2=ops.begin(); it2!=ops.end(); it2++, i++) + if ((*it2)->id == parent) + break; + op = *it2; + } + + std::sort(rows.begin(), rows.end()); + + for(i=0; i<(int)rows.size(); i++) + { + if (rows[i] >= i) + { + if (ops[i]->meta) + RemoveMeta(ops[i], rows[i]-i, true, false); + else + { + DeleteRows(rows[i]-i, 1); + _displayedOperations.erase(_displayedOperations.begin()+rows[i]-i); + } + } + else + { + if (ops[i]->meta) + RemoveMeta(ops[i], rows[i], true, false); + else + { + DeleteRows(rows[i], 1); + _displayedOperations.erase(_displayedOperations.begin()+rows[i]); + } + } + } + + UpdateMeta(op, ops); + + for(it2=ops.begin(); it2!=ops.end(); it2++) + { + for (i=0, it3=op->childs.begin(); it3!=op->childs.end(); it3++, i++) + if ((*it3)->id == (*it2)->id || + (*it3)->day > (*it2)->day) + break; + + if (i) i--; + + if (it3 == op->childs.end()) + op->childs.push_back(*it2); + else if ((*it3)->id == (*it2)->id) + continue; + else + op->childs.insert(op->childs.begin()+i, *it2); + + (*it2)->parent = op->id; + _kiss->UpdateOperation(**it2); + } + + _kiss->UpdateOperation(*op); + InsertIntoGrid(op); } void GridAccount::UnGroup() diff --git a/src/view/grid/GridAccount.h b/src/view/grid/GridAccount.h index e5c9d82..5f9cd68 100644 --- a/src/view/grid/GridAccount.h +++ b/src/view/grid/GridAccount.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -65,8 +66,11 @@ private: void SetWeek(int week, int line); void ResetWeeks(); + void InsertIntoGrid(Operation* op); void DeleteOperation(const Operation& op); - + void UpdateMeta(Operation* op, std::vector ops); + void RemoveMeta(Operation* op, int line, bool removeRoot, bool deleteOp); + DECLARE_EVENT_TABLE(); }; #endif