diff --git a/Makefile b/Makefile index db1de5f..1eaff8f 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ CXXFLAGS+=-Wall ifdef WIN32 CXXFLAGS+=-DRESOURCES_ROOT="\"./resources/\"" -static else -CXXFLAGS+=-DRESOURCES_ROOT="\"$(SHARE_DIR)\"" -ggdb -fPIC +CXXFLAGS+=-DRESOURCES_ROOT="\"$(SHARE_DIR)\"" -ggdb -fPIC -O0 # For developpers #CXXFLAGS+=-DRESOURCES_ROOT="\"./resources/\"" endif diff --git a/resources/init.sql b/resources/init.sql index 0e28a23..0dce399 100755 --- a/resources/init.sql +++ b/resources/init.sql @@ -1,6 +1,6 @@ CREATE TABLE kisscount(db_version VARCHAR(20)); CREATE TABLE user (id INTEGER PRIMARY KEY, name VARCHAR(255), password VARCHAR(255)); -CREATE TABLE account(id INTEGER PRIMARY KEY, user REFERENCES user(id), name VARCHAR(255), number VARCHAR(255), shared CHAR(1), blocked CHAR(1), default_account CHAR(1), virtual CHAR(1), hidden CHAR(1)); +CREATE TABLE account(id INTEGER PRIMARY KEY, user REFERENCES user(id), name VARCHAR(255), number VARCHAR(255), shared CHAR(1), blocked CHAR(1), default_account CHAR(1), virtual CHAR(1), hidden CHAR(1), start DATE, end DATE); CREATE TABLE shared_account(account REFERENCES account(id), user REFERENCES user(id)); CREATE TABLE account_amount(account REFERENCES account(id), year INTEGER, month INTEGER, amount INTEGER, PRIMARY KEY(account, year, month)); CREATE TABLE operation(id INTEGER PRIMARY KEY, parent REFERENCES operation(id), user REFERENCES user(id), account REFERENCES account(id) ON DELETE SET NULL, year INTEGER, month INTEGER, day INTEGER, amount INTEGER, description VARCHAR(255), category REFERENCES category(id) ON DELETE SET NULL, fix_cost CHAR(1), checked CHAR(1), formula VARCHAR(255), transfert REFERENCES operation(id), meta CHAR(1), virtual CHAR(1), tag REFERENCES tag(id)); diff --git a/src/model/Account.hpp b/src/model/Account.hpp index c384479..61e2e72 100644 --- a/src/model/Account.hpp +++ b/src/model/Account.hpp @@ -20,6 +20,8 @@ #ifndef ACCOUNT_H #define ACCOUNT_H +#include + struct Account { int id; QString name; @@ -30,7 +32,9 @@ struct Account { bool is_owner; bool _virtual; bool hidden; - + QDate start_date; + QDate end_date; + bool operator() (const Account& ac1, const Account& ac2) const { if (ac1._default) return true; @@ -52,6 +56,36 @@ struct Account { { return id == accountId; } + + bool validAt(int day, int month, int year) + { + QDate targetDate = QDate(year, month+1, day+1); + + return (targetDate >= start_date && + targetDate <= end_date); + } + + bool validAt(int month, int year) + { + QDate targetDateS = QDate(year, month+1, 01); + QDate targetDateE = targetDateS.addMonths(1).addDays(-1); + + return !(end_date < targetDateS || + start_date > targetDateE); + + } + + bool validAt(int month_start, int year_start, + int month_end, int year_end) + { + QDate targetDateS = QDate(year_start, month_start+1, 01); + QDate targetDateE = QDate(year_end, month_end+1, 01); + targetDateE = targetDateE.addMonths(1).addDays(-1); + + return !(end_date < targetDateS || + start_date > targetDateE); + + } }; #endif diff --git a/src/model/Database.cpp b/src/model/Database.cpp index d1e0fe2..c1feba4 100644 --- a/src/model/Database.cpp +++ b/src/model/Database.cpp @@ -210,6 +210,8 @@ static inline void fillAccount(Account* account, const QSqlRecord& set) account->_virtual = set.value("virtual").toBool(); account->is_owner = true; account->hidden = set.value("hidden").toBool(); + account->start_date = set.value("start").toDate(); + account->end_date = set.value("end").toDate(); } static inline void fillCategory(Category* category, const QSqlRecord& set) @@ -812,6 +814,12 @@ void Database::UpdateAccount(Account& ac) EXECUTE_SQL_UPDATE(req, ); + req = "UPDATE account SET start='%1', end='%2' WHERE id='%3'" ; + req = req.arg(ac.start_date.toString("yyyy-MM-dd"), ac.end_date.toString("yyyy-MM-dd"), + QString::number(ac.id)); + + EXECUTE_SQL_UPDATE(req, ); + if (!ac.shared && ac.is_owner) { req = QString("DELETE FROM shared_account WHERE account='%1'").arg(ac.id); diff --git a/src/model/Database.hpp b/src/model/Database.hpp index 770330e..d329e0e 100644 --- a/src/model/Database.hpp +++ b/src/model/Database.hpp @@ -126,7 +126,7 @@ public: static const int NOT_CHECKED_OP = (1 << 3); static const int ALL_OP = (~0); - static const int VERSION = 4; + static const int VERSION = 5; Database(const char* filename, KissCount* kiss); diff --git a/src/model/DatabaseUpdate.cpp b/src/model/DatabaseUpdate.cpp index 3665f9c..0f33af2 100644 --- a/src/model/DatabaseUpdate.cpp +++ b/src/model/DatabaseUpdate.cpp @@ -100,22 +100,38 @@ static void Version_3_to_4(QSqlDatabase& _db) req = "CREATE TABLE tag(id INTEGER PRIMARY KEY, user REFERENCES user(id), name VARCHAR(255));"; - UPDATE_TABLE("2", "3", "1"); + UPDATE_TABLE("3", "3", "1"); /* Account */ req = "ALTER TABLE operation ADD tag REFERENCES tag(id)"; - UPDATE_TABLE("2", "3", "2"); + UPDATE_TABLE("3", "3", "2"); req = "UPDATE operation SET tag='0'"; - UPDATE_TABLE("2", "3", "3"); + UPDATE_TABLE("3", "3", "3"); +} + +static void Version_4_to_5(QSqlDatabase& _db) +{ + QString req ; + + /* Account */ + req = "ALTER TABLE account ADD COLUMN start DATE;"; + UPDATE_TABLE("4", "5", "5"); + + req = "ALTER TABLE account ADD COLUMN end DATE;"; + UPDATE_TABLE("4", "5", "6"); + + req = "UPDATE account SET start='1900-01-01', end='2050-12-31';"; + UPDATE_TABLE("4", "5", "11"); } static update_func updates[] = { Version_1_to_2, Version_2_to_3, - Version_3_to_4 + Version_3_to_4, + Version_4_to_5 }; void Database::CheckDatabaseVersion() diff --git a/src/view/AccountPanel.cpp b/src/view/AccountPanel.cpp index 61b8359..f277264 100644 --- a/src/view/AccountPanel.cpp +++ b/src/view/AccountPanel.cpp @@ -485,14 +485,15 @@ void AccountPanel::InitAccountsGrid(User* user, int month, int year) nbAccounts = 0; for (it = user->_accounts.begin(); it != user->_accounts.end(); it++) { - if (!it->hidden) nbAccounts++; + 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) + if (it->hidden || !it->validAt(month, year)) { value = _kiss->GetAccountAmount(it->id, month, year); _accountsInitValues[it->id] = value; @@ -670,7 +671,9 @@ void AccountPanel::UpdateStats() for (intIt=curAccountAmounts[i].begin(); intIt!=curAccountAmounts[i].end(); intIt++) { - if (user->GetAccount(intIt->first).hidden || user->GetAccount(intIt->first)._virtual) + account = user->GetAccount(intIt->first); + if (account.hidden || account._virtual || + !account.validAt(i, _curMonth, _curYear)) continue; if (curAccountAmounts[i][intIt->first] < minimalValue) @@ -716,7 +719,7 @@ void AccountPanel::UpdateStats() for (i=0, accountIt=user->_accounts.begin(); accountIt!=user->_accounts.end(); accountIt++, i++) { - if (accountIt->hidden) + if (accountIt->hidden || !accountIt->validAt(_curMonth, _curYear)) { i--; continue; diff --git a/src/view/PreferencesPanel.cpp b/src/view/PreferencesPanel.cpp index 84eb3db..9a2353f 100644 --- a/src/view/PreferencesPanel.cpp +++ b/src/view/PreferencesPanel.cpp @@ -30,8 +30,9 @@ #include "PreferencesPanel.hpp" #include "grid/StarDelegate.hpp" +#include "grid/CalendarDelegate.hpp" -enum {ACCOUNT_NAME, ACCOUNT_NUMBER, ACCOUNT_DEFAULT, ACCOUNT_VIRTUAL, ACCOUNT_BLOCKED, ACCOUNT_DELETE, ACCOUNT_HIDDEN, NUMBER_COLS_ACCOUNT}; +enum {ACCOUNT_NAME, ACCOUNT_NUMBER, ACCOUNT_DEFAULT, ACCOUNT_VIRTUAL, ACCOUNT_BLOCKED, ACCOUNT_START, ACCOUNT_END, ACCOUNT_DELETE, ACCOUNT_HIDDEN, NUMBER_COLS_ACCOUNT}; enum {CATEGORY_NAME, CATEGORY_BACKGROUND_COLOR, CATEGORY_FOREGROUND_COLOR, CATEGORY_FONT, CATEGORY_DELETE, NUMBER_COLS_CATEGORY}; enum {TAG_NAME, TAG_DELETE, NUMBER_COLS_TAG}; @@ -102,14 +103,18 @@ PreferencesPanel::PreferencesPanel(KissCount* kiss, wxUI *parent, bool lowResolu _accountsGrid = new QTableWidget(); - StarDelegate* starDelegate = new StarDelegate(this, &user->_accounts); - _accountsGrid->setItemDelegateForColumn(ACCOUNT_NUMBER, starDelegate); + CalendarDelegate* calendarDelegate = new CalendarDelegate(this, &user->_accounts, true, _kiss->GetDateFormat()); + _accountsGrid->setItemDelegateForColumn(ACCOUNT_START, calendarDelegate); + + calendarDelegate = new CalendarDelegate(this, &user->_accounts, false, _kiss->GetDateFormat()); + _accountsGrid->setItemDelegateForColumn(ACCOUNT_END, calendarDelegate); InitAccounts(user); connect(_accountsGrid, SIGNAL(cellChanged(int, int)), this, SLOT(OnAccountModified(int, int))); connect(_accountsGrid, SIGNAL(currentCellChanged(int, int, int, int)), this, SLOT(OnAccountCellChanged(int, int, int, int))); + staticBoxSizer->addWidget(_accountsGrid); hbox1->addWidget(staticAccount); @@ -240,6 +245,8 @@ void PreferencesPanel::InitAccounts(User* user) _accountsGrid->setHorizontalHeaderItem(ACCOUNT_DEFAULT, new QTableWidgetItem(_("Default"))); _accountsGrid->setHorizontalHeaderItem(ACCOUNT_VIRTUAL, new QTableWidgetItem(_("Virtual"))); _accountsGrid->setHorizontalHeaderItem(ACCOUNT_BLOCKED, new QTableWidgetItem(_("Blocked"))); + _accountsGrid->setHorizontalHeaderItem(ACCOUNT_START, new QTableWidgetItem(_("Start"))); + _accountsGrid->setHorizontalHeaderItem(ACCOUNT_END, new QTableWidgetItem(_("End"))); _accountsGrid->setHorizontalHeaderItem(ACCOUNT_DELETE, new QTableWidgetItem(_("Delete"))); _accountsGrid->setHorizontalHeaderItem(ACCOUNT_HIDDEN, new QTableWidgetItem(_("Hidden"))); @@ -304,6 +311,9 @@ void PreferencesPanel::AddAccount(int line, Account ac) _hiddenAccountSignalMapper.setMapping(checkBox, ac.id); connect(checkBox, SIGNAL(stateChanged(int)), &_hiddenAccountSignalMapper, SLOT(map())); + _accountsGrid->setItem(line, ACCOUNT_START, new QTableWidgetItem(ac.start_date.toString(_kiss->GetDateFormat()))); + _accountsGrid->setItem(line, ACCOUNT_END, new QTableWidgetItem(ac.end_date.toString(_kiss->GetDateFormat()))); + for(int i=0; iitem(line, i)) _accountsGrid->setItem(line, i, new QTableWidgetItem("")); @@ -318,6 +328,8 @@ void PreferencesPanel::AddAccount(int line, Account ac) SET_READ_ONLY(line, ACCOUNT_NUMBER); SET_READ_ONLY(line, ACCOUNT_DEFAULT); SET_READ_ONLY(line, ACCOUNT_VIRTUAL); + SET_READ_ONLY(line, ACCOUNT_START); + SET_READ_ONLY(line, ACCOUNT_END); SET_READ_ONLY(line, ACCOUNT_BLOCKED); SET_READ_ONLY(line, ACCOUNT_HIDDEN); } @@ -331,6 +343,11 @@ void PreferencesPanel::AddAccount(int line, Account ac) } else { + QDate date = QDate::currentDate(); + _accountsGrid->setItem(line, ACCOUNT_START, new QTableWidgetItem(date.toString(_kiss->GetDateFormat()))); + date = date.addYears(30); + _accountsGrid->setItem(line, ACCOUNT_END, new QTableWidgetItem(date.toString(_kiss->GetDateFormat()))); + for(int i=0; iitem(line, i)) _accountsGrid->setItem(line, i, new QTableWidgetItem("")); @@ -964,7 +981,7 @@ void PreferencesPanel::OnFontClicked(int id) void PreferencesPanel::OnAccountModified(int row, int col) { - int op_complete = 1, new_id; + int op_complete = 3, new_id; QString value ; Account new_account, account; User* user = _kiss->GetUser(); @@ -987,6 +1004,27 @@ void PreferencesPanel::OnAccountModified(int row, int col) //op_complete--; } + value = _accountsGrid->item(row, ACCOUNT_START)->text(); + if (value.size()) + { + new_account.start_date = QDate::fromString(value, "dd/MM/yyyy"); + op_complete--; + } + + value = _accountsGrid->item(row, ACCOUNT_END)->text(); + if (value.size()) + { + new_account.end_date = QDate::fromString(value, "dd/MM/yyyy"); + op_complete--; + + if (new_account.end_date < new_account.start_date) + { + QMessageBox::critical(0, _("Error"), _("End date before start date")); + _inModification = false; + return ; + } + } + // Account modification if (user->GetAccountsNumber() && row < user->GetAccountsNumber()) { diff --git a/src/view/PreferencesPanel.hpp b/src/view/PreferencesPanel.hpp index 09f9dba..6d138d6 100644 --- a/src/view/PreferencesPanel.hpp +++ b/src/view/PreferencesPanel.hpp @@ -75,6 +75,7 @@ private: std::map _sharedOwners; QSignalMapper _defaultSignalMapper, _virtualSignalMapper, _blockedSignalMapper, _deleteAccountSignalMapper, _hiddenAccountSignalMapper, _deleteCategorySignalMapper, _deleteTagSignalMapper, _backgroundColorSignalMapper, _foregroundColorSignalMapper, _fontSignalMapper; bool _inModification; + void InitAccounts(User* user); void InitCategories(User* user); void InitTags(User* user); diff --git a/src/view/StatsPanel.cpp b/src/view/StatsPanel.cpp index 4f5dd6d..c00f1d1 100644 --- a/src/view/StatsPanel.cpp +++ b/src/view/StatsPanel.cpp @@ -41,7 +41,6 @@ StatsPanel::StatsPanel(KissCount* kiss, wxUI *parent, bool lowResolution) : std::vector::iterator categoryIt; std::map > operations; std::map >::iterator it; - QListWidgetItem* item; _icons[KissPanel::LOW_RES_ICON] = STATS_LOW_ICON; _icons[KissPanel::HIGH_RES_ICON] = STATS_ICON; @@ -97,11 +96,7 @@ StatsPanel::StatsPanel(KissCount* kiss, wxUI *parent, bool lowResolution) : _account = new QListWidget(this); for(i=0, accountIt = user->_accounts.begin(); accountIt != user->_accounts.end(); accountIt++, i++) { - item = new QListWidgetItem(accountIt->name, _account); - if (accountIt->hidden) - item->setCheckState (Qt::Unchecked); - else - item->setCheckState (Qt::Checked); + _account->addItem(accountIt->name); } _account->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); @@ -330,7 +325,11 @@ void StatsPanel::OnShow() void StatsPanel::OnRangeChange(int index) { int monthFrom, monthTo, yearFrom, yearTo; - + QListWidgetItem* item; + std::vector::iterator accountIt; + int i; + User* user = _kiss->GetUser(); + monthFrom = _monthFrom->currentIndex(); yearFrom = _yearFrom->currentText().toInt(); monthTo = _monthTo->currentIndex(); @@ -343,6 +342,15 @@ void StatsPanel::OnRangeChange(int index) return; } + for(i=0, accountIt = user->_accounts.begin(); accountIt != user->_accounts.end(); accountIt++, i++) + { + item = _account->item(i); + if (accountIt->hidden || !accountIt->validAt(monthFrom, yearFrom, monthTo, yearTo)) + item->setCheckState (Qt::Unchecked); + else + item->setCheckState (Qt::Checked); + } + _costRepartitionBanner->Reset(); UpdateStats(monthFrom, yearFrom, monthTo, yearTo); } diff --git a/src/view/grid/CalendarDelegate.cpp b/src/view/grid/CalendarDelegate.cpp new file mode 100644 index 0000000..116cd01 --- /dev/null +++ b/src/view/grid/CalendarDelegate.cpp @@ -0,0 +1,77 @@ +/* + Copyright 2017 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 "CalendarDelegate.hpp" + +void CalendarDelegate::OnCalendarClicked(const QDate &date) +{ + _date = date; + commitData(qobject_cast(sender())); + closeEditor(qobject_cast(sender()), QAbstractItemDelegate::SubmitModelCache); +} + +QWidget * CalendarDelegate::createEditor (QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const +{ + QCalendarWidget* calendar = new QCalendarWidget(parent); + + calendar->setGridVisible(false); + calendar->setFirstDayOfWeek(Qt::Monday); + calendar->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + calendar->setMinimumWidth(300); + calendar->setMinimumHeight(200); + + connect(calendar, SIGNAL(clicked (const QDate&)), this, SLOT(OnCalendarClicked(const QDate&))); + + return calendar; +} + +void CalendarDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const +{ + if (index.row() < (int)_accounts->size()) + { + Account ac = (*_accounts)[index.row()]; + if (_start) + ac.start_date = _date; + else + ac.end_date = _date; + } + model->setData(index, qVariantFromValue(_date.toString(_dateFormat))); +} + +void CalendarDelegate::setEditorData(QWidget *editor, + const QModelIndex &index) const +{ + QCalendarWidget *calendar = qobject_cast(editor); + + if (index.row() >= (int)_accounts->size()) + calendar->setSelectedDate(_date); + else + { + Account ac = (*_accounts)[index.row()]; + if (_start) + calendar->setSelectedDate(ac.start_date); + else + calendar->setSelectedDate(ac.end_date); + } +} diff --git a/src/view/grid/CalendarDelegate.hpp b/src/view/grid/CalendarDelegate.hpp new file mode 100644 index 0000000..1750c03 --- /dev/null +++ b/src/view/grid/CalendarDelegate.hpp @@ -0,0 +1,51 @@ +/* + Copyright 2017 Grégory Soutadé + + This file is part of KissCount. + + KissCount is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + KissCount is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with KissCount. If not, see . +*/ + +#ifndef CALENDARDELEGATE_H +#define CALENDARDELEGATE_H + +#include +#include +#include +#include + +class CalendarDelegate : public QStyledItemDelegate +{ + Q_OBJECT; + +public: + CalendarDelegate(QWidget *parent = 0, std::vector* accounts=0, bool start=true, QString dateFormat="dd/MM/yyyy") : + QStyledItemDelegate(parent), _accounts(accounts), _start(start), _dateFormat(dateFormat) {} + + QWidget * createEditor ( QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const; + void setEditorData(QWidget *editor, const QModelIndex &index) const; + void setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const; + +private slots: + void OnCalendarClicked(const QDate &date); + +private: + std::vector* _accounts; + bool _start; + QDate _date; + QString _dateFormat; +}; + +#endif