KissCount

KissCount Commit Details

Date:2014-11-10 11:54:28 (5 years 8 months ago)
Author:Grégory Soutadé
Branch:dev, master, qt5
Commit:57d4b90182b0cadc310ebe9e7f28b1205f8a22ec
Parents: 899dc3db719658cdde40cc148e2ee1538f811143
Message:Tag management : first version

Changes:
Mressources/init.sql (1 diff)
Msrc/controller/KissCount.cpp (4 diffs)
Msrc/controller/KissCount.hpp (2 diffs)
Msrc/model/Database.cpp (12 diffs)
Msrc/model/Database.hpp (3 diffs)
Msrc/model/DatabaseUpdate.cpp (1 diff)
Msrc/model/Operation.hpp (1 diff)
Msrc/model/User.cpp (2 diffs)
Msrc/model/User.hpp (4 diffs)
Msrc/model/export/CSVExportEngine.cpp (3 diffs)
Msrc/model/export/CSVExportEngine.hpp (1 diff)
Msrc/model/export/ExportEngine.hpp (1 diff)
Msrc/model/export/XMLExportEngine.cpp (3 diffs)
Msrc/model/export/XMLExportEngine.hpp (1 diff)
Msrc/model/import/GrisbiImportEngine.cpp (1 diff)
Msrc/model/import/ImportEngine.cpp (5 diffs)
Msrc/model/import/ImportEngine.hpp (3 diffs)
Msrc/model/import/OFXImportEngine.cpp (1 diff)
Msrc/model/import/XMLImportEngine.cpp (3 diffs)
Msrc/model/import/XMLImportEngine.hpp (1 diff)
Msrc/view/AccountPanel.cpp (3 diffs)
Msrc/view/AccountPanel.hpp (1 diff)
Msrc/view/ImportPanel.cpp (12 diffs)
Msrc/view/ImportPanel.hpp (2 diffs)
Msrc/view/PreferencesPanel.cpp (8 diffs)
Msrc/view/PreferencesPanel.hpp (3 diffs)
Msrc/view/SearchBanner.cpp (7 diffs)
Msrc/view/SearchBanner.hpp (1 diff)
Msrc/view/StatsPanel.cpp (3 diffs)
Msrc/view/grid/ChoiceDelegate.hpp (1 diff)
Msrc/view/grid/GridAccount.cpp (18 diffs)
Msrc/view/grid/GridAccount.hpp (2 diffs)

File differences

ressources/init.sql
33
44
55
6
6
77
88
99
10
10
11
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 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));
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));
CREATE TABLE category(id INTEGER PRIMARY KEY, user REFERENCES user(id), parent REFERENCES category(id) ON DELETE SET NULL, name VARCHAR(255), backcolor VARCHAR(10), forecolor VARCHAR(10), font VARCHAR(255), fix_cost CHAR(1));
CREATE TABLE preference(user REFERENCES user(id), name VARCHAR(255), value VARCHAR(255), PRIMARY KEY(user, name));
CREATE TABLE import_pattern(user REFERENCES user(id), description VARCHAR(255), pattern VARCHAR(255), account REFERENCES account(id), category REFERENCES category(id), PRIMARY KEY(user, description));
INSERT INTO kisscount ("db_version") VALUES ("3");
CREATE TABLE tag(id INTEGER PRIMARY KEY, user REFERENCES user(id), name VARCHAR(255));
INSERT INTO kisscount ("db_version") VALUES ("4");
src/controller/KissCount.cpp
251251
252252
253253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
254281
255282
256283
......
411438
412439
413440
414
441
442
415443
416444
417
445
418446
419447
420448
......
434462
435463
436464
437
465
438466
439
467
440468
441469
442470
......
471499
472500
473501
474
502
475503
476
504
477505
478506
479507
480508
481
509
482510
483
511
484512
485513
486514
LoadYear(it->first, true);
}
int KissCount::AddTag(Tag& tag)
{
tag.id = _db->AddTag(_user, tag);
_user->AddTag(tag);
return tag.id;
}
void KissCount::UpdateTag(Tag& tag)
{
_db->UpdateTag(tag);
_user->UpdateTag(tag);
}
void KissCount::DeleteTag(Tag& tag, int replacement)
{
std::map<unsigned int, std::map<unsigned int, std::vector<Operation> >* >::iterator it;
_db->DeleteTag(_user, tag, replacement);
_user->DeleteTag(tag);
for (it= _user->_operations.begin();
it != _user->_operations.end();
it++)
LoadYear(it->first, true);
}
std::map<int, std::vector<int> > KissCount::GetAllOperations()
{
return _db->GetAllOperations(_user);
std::vector<Operation>* KissCount::Search(QString* description, QDate* dateFrom, QDate* dateTo,
int* amountFrom, int* amountTo,
std::vector<int> categories, int types, std::vector<int> accounts)
std::vector<int> categories,
int types, std::vector<int> accounts, std::vector<int> tags)
{
return _db->Search(_user, description, dateFrom, dateTo, amountFrom, amountTo, categories, types, accounts, true);
return _db->Search(_user, description, dateFrom, dateTo, amountFrom, amountTo, categories, types, accounts, true, tags);
}
bool KissCount::SearchPreviousOperation(Operation* res, Operation& op, int month, int year, bool limitToType, int index)
QDate date = QDate(year, month, 0);
if (limitToType)
operations = _db->Search(_user, &op.description, &date, 0, 0, 0, v, op.fix_cost ? +Database::FIX_OP : +Database::NON_FIX_OP, v, false);
operations = _db->Search(_user, &op.description, &date, 0, 0, 0, v, op.fix_cost ? +Database::FIX_OP : +Database::NON_FIX_OP, v, false, v);
else
operations = _db->Search(_user, &op.description, &date, 0, 0, 0, v, Database::ALL_OP, v, false);
operations = _db->Search(_user, &op.description, &date, 0, 0, 0, v, Database::ALL_OP, v, false, v);
if (!operations->size())
{
void KissCount::GetStats(int monthFrom, int yearFrom, int monthTo, int yearTo,
std::map<int, std::map<int, std::map<int, int> > >* accountAmounts,
std::map<int, int>* categories)
std::map<int, int>* categories, std::map<int, int>* tags)
{
_db->GetStats(_user, monthFrom, yearFrom, monthTo, yearTo, accountAmounts, categories);
_db->GetStats(_user, monthFrom, yearFrom, monthTo, yearTo, accountAmounts, categories, tags);
}
void KissCount::GetMonthStats(int month, int year, int nbDays,
std::map<int, std::vector<int> >* operations,
std::map<int, int>* categories)
std::map<int, int>* categories, std::map<int, int>* tags)
{
_db->GetMonthStats(_user, month, year, nbDays, operations, categories);
_db->GetMonthStats(_user, month, year, nbDays, operations, categories, tags);
}
void KissCount::UpdateStats()
src/controller/KissCount.hpp
9393
9494
9595
96
97
98
99
96100
97101
98102
......
104108
105109
106110
107
111
112
108113
109114
110115
111116
112117
113
118
114119
115120
116121
117
122
118123
119124
120125
void UpdateCategory(Category& category);
void DeleteCategory(Category& category, int replacement);
int AddTag(Tag& tag);
void UpdateTag(Tag& tag);
void DeleteTag(Tag& tag, int replacement);
std::map<int, std::vector<int> > GetAllOperations();
int GenerateMonth(int monthFrom, int yearFrom, int monthTo, int yearTo);
std::vector<Operation>* Search(QString* description, QDate* dateFrom, QDate* dateTo,
int* amountFrom, int* amountTo,
std::vector<int> categories, int types, std::vector<int> accounts);
std::vector<int> categories,
int types, std::vector<int> accounts, std::vector<int> tags);
bool SearchPreviousOperation(Operation* res, Operation& op, int month, int year, bool limitToType, int index);
void GetStats(int monthFrom, int yearFrom, int monthTo, int yearTo,
std::map<int, std::map<int, std::map<int, int> > >* accountAmounts,
std::map<int, int>* categories);
std::map<int, int>* categories, std::map<int, int>* tags);
void GetMonthStats(int month, int year, int nbDays,
std::map<int, std::vector<int> >* operations,
std::map<int, int>* categories);
std::map<int, int>* categories, std::map<int, int>* tags);
void UpdateStats();
std::map<int, int>* GetNotChecked(int month, int year);
src/model/Database.cpp
187187
188188
189189
190
190191
191192
192193
......
219220
220221
221222
223
224
225
226
227
228
222229
223230
224231
225232
226233
234
227235
228236
229237
......
311319
312320
313321
322
323
324
325
326
327
328
329
330
331
332
333
334
314335
315336
316337
......
549570
550571
551572
552
573
553574
554
575
555576
556577
557578
......
571592
572593
573594
574
595
575596
576597
577
578
598
599
579600
580601
581602
......
10011022
10021023
10031024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
10041099
10051100
10061101
......
12111306
12121307
12131308
1309
1310
1311
12141312
12151313
12161314
......
12281326
12291327
12301328
1231
1329
12321330
12331331
12341332
......
13181416
13191417
13201418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
13211433
13221434
13231435
......
13981510
13991511
14001512
1401
1513
14021514
14031515
14041516
14051517
14061518
14071519
1520
14081521
14091522
14101523
......
14731586
14741587
14751588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
14761636
14771637
14781638
14791639
14801640
1481
1641
14821642
14831643
14841644
......
15351695
15361696
15371697
1538
1698
15391699
15401700
15411701
op->amount = set.value("amount").toInt();
op->description = set.value("description").toString();
op->category = set.value("category").toInt();
op->tag = set.value("tag").toInt();
op->fix_cost = set.value("fix_cost").toBool();
op->checked = set.value("checked").toBool();
op->transfert = set.value("transfert").toInt();
category->fix_cost = set.value("fix_cost").toBool();
}
static inline void fillTag(Tag* tag, const QSqlRecord& set)
{
tag->id = set.value("id").toInt();
tag->name = set.value("name").toString();
}
User* Database::LoadUser(const QString& name)
{
User* user;
Account account;
Category category;
Tag tag;
ImportPattern importPattern;
QString req;
QSqlRecord set;
query.clear();
req = QString("SELECT * FROM tag WHERE user='%1' ORDER BY name ASC").arg(user->_id);
EXECUTE_SQL_QUERY_WITH_CODE(req, 0, {delete user;}, {delete user;});
while (query.next())
{
set = query.record();
fillTag(&tag, set);
user->_tags.push_back(tag);
}
query.clear();
req = QString("SELECT name, value FROM preference WHERE user='%1' ORDER BY value ASC").arg(user->_id);
EXECUTE_SQL_QUERY_WITH_CODE(req, 0, {delete user;}, {delete user;});
ESCAPE_CHARS(op.description);
req = "UPDATE operation SET parent='%1', account='%2', year='%3', month='%4', day='%5', amount='%6', description=\"%7\", category='%8'" ;
req = "UPDATE operation SET parent='%1', account='%2', year='%3', month='%4', day='%5', amount='%6', description=\"%7\", category='%8', tag='%9'" ;
req = req.arg((op.parent) ? QString::number(op.parent) : "", QString::number(op.account), QString::number(op.year), QString::number(op.month),
QString::number(op.day), v.sprintf("%d", op.amount), op.description, QString::number(op.category));
QString::number(op.day), v.sprintf("%d", op.amount), op.description, QString::number(op.category), QString::number(op.tag));
req += ", fix_cost='%1', checked='%2', transfert='%3', meta='%4', virtual='%5', formula='%6' WHERE id='%7'";
req = req.arg(QString::number(op.fix_cost), QString::number(op.checked), (op.transfert) ? QString::number(op.transfert): "",
QString::number(op.meta), QString::number(op._virtual), op.formula, QString::number(op.id));
ESCAPE_CHARS(op.description);
req = "INSERT INTO operation ('user', 'parent', 'account', 'year', 'month', 'day', 'amount', 'description', 'category', 'fix_cost', 'formula', 'transfert', 'meta', 'virtual', 'checked') VALUES ('%1', '%2', '%3', '%4', '%5', '%6', '%7', \"%8\"" ;
req = "INSERT INTO operation ('user', 'parent', 'account', 'year', 'month', 'day', 'amount', 'description', 'category', 'tag', 'fix_cost', 'formula', 'transfert', 'meta', 'virtual', 'checked') VALUES ('%1', '%2', '%3', '%4', '%5', '%6', '%7', \"%8\"" ;
req = req.arg(QString::number(user->_id), (op.parent) ? QString::number(op.parent): "", QString::number(op.account), QString::number(op.year),
QString::number(op.month), QString::number(op.day), v.sprintf("%d", op.amount), op.description);
req += ", '%1', '%2', '%3', '%4', '%5', '%6', '%7')";
req = req.arg(QString::number(op.category), QString::number(op.fix_cost), op.formula, (op.transfert) ? QString::number(op.transfert): "",
req += ", '%1', '%2', '%3', '%4', '%5', '%6', '%7', '%8')";
req = req.arg(QString::number(op.category), QString::number(op.tag), QString::number(op.fix_cost), op.formula, (op.transfert) ? QString::number(op.transfert): "",
QString::number(op.meta), QString::number(op._virtual), QString::number(op.checked));
if (!query.exec(req))
return ret;
}
int Database::AddTag(User* user, Tag& tag)
{
QString req;
QString backcolor, forecolor;
QSqlQuery query(_db);
req = "INSERT INTO tag ('user', 'name') VALUES ('" ;
req += QString::number(user->_id) + "'";
req += ", '" + tag.name + "'";
req += ")";
if (!query.exec(req))
{
QMessageBox::critical(0, _("Error"), _("Update failed !\n") + req);
std::cerr << __FUNCTION__ << "\n" ;
std::cerr << req.toStdString() << "\n" ;
std::cerr << query.lastError().text().toStdString() << "\n" ;
return 0;
}
return query.lastInsertId().toInt();
}
void Database::UpdateTag(Tag& tag)
{
QString req;
req = "UPDATE tag SET" ;
req += "name='" + tag.name + "'";
req += " WHERE id='" + QString::number(tag.id) + "'";
EXECUTE_SQL_UPDATE(req, );
}
void Database::DeleteTag(User* user, Tag& tag, int replacement)
{
QString req;
req = QString("DELETE FROM tag WHERE id='%1'").arg(tag.id);
EXECUTE_SQL_UPDATE(req, );
req = QString("UPDATE operation SET tag='%1' WHERE tag='%2' AND user='%3'")
.arg(QString::number(replacement), QString::number(tag.id), QString::number(user->_id));
EXECUTE_SQL_UPDATE(req, );
}
bool Database::LoadTag(int id, const QString& name, Tag& tag)
{
QSqlRecord set;
QString req;
QSqlQuery query(_db);
bool ret = false ;
if (id)
req = QString("SELECT * FROM tag WHERE id='%1'").arg(id);
else
req = QString("SELECT * FROM tag WHERE name='%1'").arg(name);
EXECUTE_SQL_QUERY(req, false);
if (query.next())
{
set = query.record();
fillTag(&tag, set);
ret = true;
}
query.clear();
return ret;
}
std::map<int, std::vector<int> > Database::GetAllOperations(User* user)
{
QString req, req2, reqUnion;
req = QString("DELETE FROM category WHERE user='%1'").arg(user->_id);
EXECUTE_SQL_UPDATE(req, );
req = QString("DELETE FROM tag WHERE user='%1'").arg(user->_id);
EXECUTE_SQL_UPDATE(req, );
req = QString("DELETE FROM user WHERE id='%1'").arg(user->_id);
EXECUTE_SQL_UPDATE(req, );
}
std::vector<Operation>* Database::Search(User* user, QString* description, QDate* dateFrom, QDate* dateTo,
int* amountFrom, int* amountTo,
std::vector<int> categories, int types, std::vector<int> accounts, bool wildcards)
std::vector<int> categories, int types, std::vector<int> accounts, bool wildcards, std::vector<int> tags)
{
QSqlRecord set;
QSqlQuery query(_db);
req += "')";
}
if (tags.size())
{
if (firstCond) req += " AND " ; else firstCond = true;
req += "category IN ('";
it = tags.begin();
req += QString::number(*it);
it++;
for (; it != tags.end(); it++)
req += "', '" + QString::number(*it) ;
req += "')";
}
if (types)
{
if (((types & Database::FIX_OP) && !(types & Database::NON_FIX_OP)) ||
void Database::GetStats(User* user, int monthFrom, int yearFrom, int monthTo,
int yearTo, std::map<int, std::map<int, std::map<int, int> > >* accountAmounts,
std::map<int, int>* categories)
std::map<int, int>* categories, std::map<int, int>* tags)
{
QSqlRecord set;
QSqlQuery query(_db);
QString req, req2;
std::vector<Account>::iterator accountIt;
std::vector<Category>::iterator categoryIt;
std::vector<Tag>::iterator tagIt;
if (!user->_accounts.empty())
{
query.clear();
}
}
if (tags)
{
for (tagIt = user->_tags.begin(); tagIt != user->_tags.end(); tagIt++)
{
req = "SELECT SUM(amount) as amount FROM operation AS o1 WHERE tag='" + QString::number(tagIt->id) + "'";
accountIt = user->_accounts.begin();
req += " AND (account IN('" + QString::number(accountIt->id);
accountIt++;
for (;accountIt != user->_accounts.end(); accountIt++)
{
req += "', '" + QString::number(accountIt->id) ;
}
req += "')";
req += " OR user='" + QString::number(user->_id) + "')";
req += " AND (year > '" + QString::number(yearFrom) + "' OR (year == '" + QString::number(yearFrom) + "' AND month >= '" + QString::number(monthFrom) + "'))";
req += " AND (year < '" + QString::number(yearTo) + "' OR (year == '" + QString::number(yearTo) + "' AND month <= '" + QString::number(monthTo) + "'))";
req += " AND meta='0'";
req2 = req + " AND (transfert='' OR transfert IS 0)";
req2 += " AND amount < 0";
EXECUTE_SQL_QUERY(req2, );
if (query.next())
{
set = query.record();
(*tags)[tagIt->id] = -set.value("amount").toInt();
}
query.clear();
// Transfert on blocked accounts must be computed
req2 = req + " AND transfert != ''";
req2 += " AND (SELECT blocked FROM account WHERE id=o1.account)";
req2 += " AND amount > 0";
EXECUTE_SQL_QUERY(req2, );
if (query.next())
{
set = query.record();
(*tags)[tagIt->id] += set.value("amount").toInt();
}
query.clear();
}
}
}
}
void Database::GetMonthStats(User* user, int month, int year, int nbDays,
std::map<int, std::vector<int> >* operations,
std::map<int, int>* categories)
std::map<int, int>* categories, std::map<int, int>* tags)
{
QSqlRecord set;
QSqlQuery query(_db);
}
// Fill categories
GetStats(user, month, year, month, year, 0, categories) ;
GetStats(user, month, year, month, year, 0, categories, tags) ;
}
std::map<int, int>* Database::GetNotChecked(User* user, int month, int year)
src/model/Database.hpp
8888
8989
9090
91
91
9292
9393
9494
......
128128
129129
130130
131
132
133
134
135
131136
132137
133138
......
140145
141146
142147
143
148
144149
145150
146151
147
152
148153
149154
150155
151
156
152157
153158
154159
static const int NOT_CHECKED_OP = (1 << 3);
static const int ALL_OP = (~0);
static const int VERSION = 3;
static const int VERSION = 4;
Database(const char* filename, KissCount* kiss);
void DeleteCategory(User* user, Category& category, int replacement);
bool LoadCategory(int id, const QString& name, Category& category);
int AddTag(User* user, Tag& tag);
void UpdateTag(Tag& tag);
void DeleteTag(User* user, Tag& tag, int replacement);
bool LoadTag(int id, const QString& name, Tag& tag);
std::map<int, std::vector<int> > GetAllOperations(User* user);
void GenerateMonth(User* user, int monthFrom, int yearFrom, int monthTo, int yearTo);
std::vector<Operation>* Search(User* user, QString* description, QDate* dateFrom, QDate* dateTo,
int* amountFrom, int* amountTo,
std::vector<int> categories, int types, std::vector<int> accounts, bool wildcards);
std::vector<int> categories, int types, std::vector<int> accounts, bool wildcards, std::vector<int> tags);
void GetStats(User* user, int monthFrom, int yearFrom, int monthTo,
int yearTo, std::map<int, std::map<int, std::map<int, int> > >* accountAmounts,
std::map<int, int>* categories);
std::map<int, int>* categories, std::map<int, int>* tags);
void GetMonthStats(User* user, int month, int year, int nbDays,
std::map<int, std::vector<int> >* operations,
std::map<int, int>* categories);
std::map<int, int>* categories, std::map<int, int>* tags);
void KillMe(User* user);
bool GetOperation(int id, Operation* op);
src/model/DatabaseUpdate.cpp
9494
9595
9696
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
97115
98116
99
117
118
100119
101120
102121
ON_ERROR(_("Cannot update database version 2 to version 3 because some columns needs to be deleted."));
}
static void Version_3_to_4(QSqlDatabase& _db)
{
QString req ;
req = "CREATE TABLE tag(id INTEGER PRIMARY KEY, user REFERENCES user(id), name VARCHAR(255));";
UPDATE_TABLE("2", "3", "1");
/* Account */
req = "ALTER TABLE operation ADD tag REFERENCES tag(id)";
UPDATE_TABLE("2", "3", "2");
req = "UPDATE operation SET tag='0'";
UPDATE_TABLE("2", "3", "3");
}
static update_func updates[] = {
Version_1_to_2,
Version_2_to_3
Version_2_to_3,
Version_3_to_4
};
void Database::CheckDatabaseVersion()
src/model/Operation.hpp
4040
4141
4242
43
4344
4445
4546
bool meta;
bool _virtual;
std::vector<int> childs;
int tag;
bool operator == (int opId)
{
src/model/User.cpp
149149
150150
151151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
152222
153223
154224
......
214284
215285
216286
287
288
289
290
291
217292
218293
219294
}
}
Tag User::GetTag(int tagId)
{
Tag tag;
std::vector<Tag>::iterator it = std::find(_tags.begin(), _tags.end(), tagId);
if (it !=_tags.end()) return *it;
if (_db->LoadTag(tagId, "", tag))
return tag;
tag.id = 0;
tag.name = "";
return tag;
}
QString User::GetTagName(int tagId)
{
Tag tag;
std::vector<Tag>::iterator it = std::find(_tags.begin(), _tags.end(), tagId);
if (it !=_tags.end()) return it->name;
if (_db->LoadTag(tagId, "", tag))
return tag.name;
return _("Unknown") ;
}
int User::GetTagId(const QString& tagName) throw (TagNotFound)
{
std::vector<Tag>::iterator it;
Tag tag;
for (it=_tags.begin(); it !=_tags.end(); it++)
if (_(it->name.toStdString().c_str()) == tagName)
return it->id;
if ( _db->LoadTag(0, tagName, tag))
return tag.id;
throw TagNotFound();
}
void User::AddTag(const Tag& tag)
{
_tags.push_back(tag);
}
void User::UpdateTag(const Tag& tag)
{
std::vector<Tag>::iterator it = std::find(_tags.begin(), _tags.end(), tag.id);
if (it !=_tags.end())
{
*it = tag;
}
}
void User::DeleteTag(const Tag& tag)
{
std::vector<Tag>::iterator it = std::find(_tags.begin(), _tags.end(), tag.id);
if (it !=_tags.end())
{
int pos = it - _tags.begin();
_tags.erase(_tags.begin()+pos);
}
}
Account User::GetAccount(int accountId) throw (AccountNotFound)
{
std::vector<Account>::iterator it = std::find(_accounts.begin(), _accounts.end(), accountId);
return _categories.size();
}
int User::GetTagsNumber()
{
return _tags.size();
}
int User::GetAccountsNumber()
{
return _accounts.size();
src/model/User.hpp
2626
2727
2828
29
2930
3031
3132
......
4748
4849
4950
51
5052
5153
5254
5355
5456
5557
58
5659
5760
5861
......
6164
6265
6366
67
68
69
70
71
72
73
6474
6575
6676
......
7383
7484
7585
86
7687
7788
7889
#include <QFont>
#include "Category.hpp"
#include "Tag.hpp"
#include "Account.hpp"
#include "Operation.hpp"
#include "Database.hpp"
std::vector<Account> _accounts;
std::map<unsigned int, std::map<unsigned int, std::vector<Operation> >* > _operations;
std::vector<Category> _categories;
std::vector<Tag> _tags;
std::vector<QFont> _categoriesFonts;
std::map<QString, QString> _preferences;
std::map<QString, ImportPattern> _importPatterns;
class AccountNotFound {};
class CategoryNotFound {};
class TagNotFound {};
Category GetCategory(int catId);
QString GetCategoryName(int catId);
void AddCategory(const Category& cat);
void UpdateCategory(const Category& cat);
void DeleteCategory(const Category& cat);
Tag GetTag(int tagId);
QString GetTagName(int tagId);
int GetTagId(const QString& tagName) throw (TagNotFound);
void AddTag(const Tag& tag);
void UpdateTag(const Tag& tag);
void DeleteTag(const Tag& tag);
Account GetAccount(int accountId) throw (AccountNotFound);
int GetCategoriesNumber();
int GetTagsNumber();
int GetAccountsNumber();
int GetOperationsNumber(int month, int year);
src/model/export/CSVExportEngine.cpp
145145
146146
147147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
148173
149174
150175
151176
152177
153178
154
179
155180
156181
157182
......
172197
173198
174199
200
175201
176202
177203
......
202228
203229
204230
231
205232
206233
207234
return true;
}
bool CSVExportEngine::SaveTags()
{
Tag tag;
std::map<int, int>::iterator it;
QString v;
*_writer << "Tags" << endl << endl;
*_writer << "id;name" << endl;
for(it=_tags.begin(); it!=_tags.end(); it++)
{
tag = _user->GetTag(it->first);
ESCAPE_CHARS(tag.name);
*_writer << QString::number(tag.id) << ";";
*_writer << "\"" << tag.name << "\"" << ";";
*_writer << endl;
}
*_writer << endl << endl;
return true;
}
bool CSVExportEngine::SaveOperations(std::vector<Operation>* operations)
{
std::vector<Operation>::iterator it;
QString v;
*_writer << "Operations" << endl << endl;
*_writer << "id;parent;day;month;year;amount;description;category;fix_cost;account;checked;transfert;formula;meta;virtual" << endl;
*_writer << "id;parent;day;month;year;amount;description;category;fix_cost;account;checked;transfert;formula;meta;virtual;tag" << endl;
for(it=operations->begin(); it!=operations->end(); it++)
{
*_writer << it->formula << ";";
*_writer << (it->meta ? "1" : "0") << ";";
*_writer << (it->_virtual ? "1" : "0");
*_writer << QString::number(it->tag) << ";";
*_writer << endl;
}
SaveAccounts();
SaveAccountAmounts();
SaveCategories();
SaveTags();
SaveOperations(operations);
file.flush();
src/model/export/CSVExportEngine.hpp
3838
3939
4040
41
4142
4243
4344
bool SaveAccounts();
bool SaveAccountAmounts();
bool SaveCategories();
bool SaveTags();
bool SaveOperations(std::vector<Operation>* operations);
};
src/model/export/ExportEngine.hpp
5555
5656
5757
58
5859
5960
6061
std::map<int, int> _accounts;
std::map<int, int> _categories;
std::map<int, int> _tags;
std::map<AccountAmount, int, AccountAmount> _accountAmounts;
};
src/model/export/XMLExportEngine.cpp
133133
134134
135135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
136157
137158
138159
......
151172
152173
153174
175
154176
155177
156178
......
191213
192214
193215
216
194217
195218
196219
return true;
}
bool XMLExportEngine::SaveTags()
{
Tag tag;
std::map<int, int>::iterator it;
QString v;
for(it=_tags.begin(); it!=_tags.end(); it++)
{
tag = _user->GetTag(it->first);
ESCAPE_CHARS(tag.name);
_writer->writeStartElement("tag");
_writer->writeAttribute("id", QString::number(tag.id));
_writer->writeAttribute("name", tag.name);
_writer->writeEndElement();
}
return true;
}
bool XMLExportEngine::SaveOperations(std::vector<Operation>* operations)
{
std::vector<Operation>::iterator it;
_writer->writeAttribute("amount", v.sprintf("%d", it->amount));
_writer->writeAttribute("description", it->description);
_writer->writeAttribute("category", QString::number(it->category));
_writer->writeAttribute("tag", QString::number(it->tag));
_writer->writeAttribute("fix_cost", (it->fix_cost ? "1" : "0"));
_writer->writeAttribute("account", QString::number(it->account));
_writer->writeAttribute("checked", (it->checked ? "1" : "0"));
SaveAccounts();
SaveAccountAmounts();
SaveCategories();
SaveTags();
SaveOperations(operations);
_writer->writeEndElement();
src/model/export/XMLExportEngine.hpp
3838
3939
4040
41
4142
4243
4344
bool SaveAccounts();
bool SaveAccountAmounts();
bool SaveCategories();
bool SaveTags();
bool SaveOperations(std::vector<Operation>* operations);
};
src/model/import/GrisbiImportEngine.cpp
101101
102102
103103
104
104105
105106
106107
op.parent = 0;
op.account = 0;
op.category = 0;
op.tag = 0;
op.fix_cost = false;
op.checked = false;
op.transfert = 0;
src/model/import/ImportEngine.cpp
196196
197197
198198
199
199200
200201
201202
......
250251
251252
252253
254
253255
254256
255257
......
281283
282284
283285
286
284287
285288
286289
......
293296
294297
295298
296
299
297300
298301
299302
303
300304
301305
302
306
303307
304308
305309
......
320324
321325
322326
327
328
329
330
331
323332
324333
325334
op.account = pattern.account;
op.category = pattern.category;
op.tag = pattern.tag;
if (pattern.pattern == NULL_IMPORT_PATTERN) return;
pattern.pattern = FindPattern(_descriptions[op.id], op.description);
pattern.account = op.account;
pattern.category = op.category;
pattern.tag = op.tag;
_user->_importPatterns[key1] = pattern;
pattern.pattern = FindPattern(originalKey, op.description);
pattern.account = op.account;
pattern.category = op.category;
pattern.tag = op.tag;
_user->_importPatterns[key1] = pattern;
}
}
void ImportEngine::ParseFile(std::vector<Account>& accounts, std::vector<Category>& categories)
void ImportEngine::ParseFile(std::vector<Account>& accounts, std::vector<Category>& categories, std::vector<Tag>& tags)
{
accounts = _unresolvedAccounts;
categories = _unresolvedCategories;
tags = _unresolvedTags;
}
std::vector<Operation>* ImportEngine::GetOperations(std::map<int, int>& accounts, std::map<int, int>& categories)
std::vector<Operation>* ImportEngine::GetOperations(std::map<int, int>& accounts, std::map<int, int>& categories, std::map<int, int>& tags)
{
int i;
std::map<AccountAmount, int, AccountAmount>::iterator it;
else
_operations[i].category = _categories[_operations[i].category];
if (_tags[_operations[i].tag] < 0)
_operations[i].tag = tags[_operations[i].tag];
else
_operations[i].tag = _tags[_operations[i].tag];
}
for(it=_accountAmounts.begin(); it!=_accountAmounts.end(); it++)
src/model/import/ImportEngine.hpp
3131
3232
3333
34
3435
3536
3637
......
5051
5152
5253
53
54
5455
5556
56
57
5758
5859
5960
......
7374
7475
7576
77
7678
7779
80
7881
7982
8083
QString pattern;
int account;
int category;
int tag;
} ;
class ImportEngine {
virtual bool HandleFile(const QString& path, User* user, Database* db, KissCount* kiss)=0;
// Parse the file and return accounts that doesn't match
virtual void ParseFile(std::vector<Account>& accounts, std::vector<Category>& categories);
virtual void ParseFile(std::vector<Account>& accounts, std::vector<Category>& categories, std::vector<Tag>& tags);
// Final Step
virtual std::vector<Operation>* GetOperations(std::map<int, int>& accounts, std::map<int, int>& categories);
virtual std::vector<Operation>* GetOperations(std::map<int, int>& accounts, std::map<int, int>& categories, std::map<int, int>& tags);
const std::map<AccountAmount, int, AccountAmount>& GetAccountAmounts();
std::map<int, int> _accounts;
std::map<int, int> _categories;
std::map<int, int> _tags;
std::vector<Account> _unresolvedAccounts;
std::vector<Category> _unresolvedCategories;
std::vector<Tag> _unresolvedTags;
std::vector<Operation> _operations;
std::map<int, QString> _descriptions;
std::map<AccountAmount, int, AccountAmount> _accountAmounts;
src/model/import/OFXImportEngine.cpp
8181
8282
8383
84
8485
8586
8687
op.id = ++id;
op.parent = 0;
op.category = 0;
op.tag = 0;
op.fix_cost = false;
op.account = _this->_curAccount;
op.checked = false;
src/model/import/XMLImportEngine.cpp
8484
8585
8686
87
88
89
8790
8891
8992
......
201204
202205
203206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
204233
205234
206235
......
213242
214243
215244
245
216246
217247
218248
else if (qName == "category")
LoadCategory(attrs);
else if (qName == "tag")
LoadTag(attrs);
else if (qName == "operation")
LoadOperation(attrs);
else
_unresolvedCategories.push_back(cat);
}
void XMLImportEngine::LoadTag(const QXmlAttributes& attrs)
{
QString name;
int id;
Tag tag;
static int unknownTag = 0;
tag.name = name = attrs.value("name");
tag.id = id = attrs.value("id").toInt();
UNESCAPE_CHARS(tag.name);
try
{
int tagId = _user->GetTagId(name);
_tags[id] = tagId;
return;
}
catch(User::TagNotFound e)
{}
_tags[id] = --unknownTag;
_unresolvedTags.push_back(tag);
}
void XMLImportEngine::LoadOperation(const QXmlAttributes& attrs)
{
Operation op;
op.amount = attrs.value("amount").toInt();
op.description = attrs.value("description");
op.category = attrs.value("category").toInt();
op.tag = attrs.value("tag").toInt();
op.fix_cost = (attrs.value("fix_cost") == "1");
op.account = attrs.value("account").toInt();
op.checked = (attrs.value("checked") == "1");
src/model/import/XMLImportEngine.hpp
4040
4141
4242
43
4344
4445
4546
void LoadAccount(const QXmlAttributes& atts);
void LoadAccountAmount(const QXmlAttributes& atts);
void LoadCategory(const QXmlAttributes& atts);
void LoadTag(const QXmlAttributes& atts);
void LoadOperation(const QXmlAttributes& atts);
};
src/view/AccountPanel.cpp
5353
5454
5555
56
5657
5758
5859
......
9293
9394
9495
96
97
98
99
100
101
102
103
104
105
106
95107
96108
97109
......
179191
180192
181193
194
195
182196
183197
184198
User* user = _kiss->GetUser();
std::vector<Account>::iterator accountIt;
std::vector<Category>::iterator categoryIt;
std::vector<Tag>::iterator tagIt;
_icons[KissPanel::LOW_RES_ICON] = USER_LOW_ICON;
_icons[KissPanel::HIGH_RES_ICON] = USER_ICON;
_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);
{
delete[] _categoriesValues;
delete[] _categories;
delete[] _tagsValues;
delete[] _tags;
delete[] _accounts;
}
src/view/AccountPanel.hpp
7777
7878
7979
80
80
8181
8282
83
8384
84
85
8586
8687
8788
GridAccount* _grid;
QTableWidget* _accountsGrid, *_statsGrid;
CostRepartitionBanner* _costRepartitionBanner;
int *_categoriesValues;
int *_categoriesValues, *_tagsValues;
// wxRadioBox *_radioMode;
std::map<QString, int> _categoriesIndexes;
std::map<QString, int> _tagsIndexes;
std::vector<Operation>* _curOperations;
QString* _categories, *_accounts;
QString* _categories, *_tags, *_accounts;
std::map<int, int> _accountsInitValues;
int _fixCosts;
QRadioButton *_virtual, *_real, *_check;
src/view/ImportPanel.cpp
3232
3333
3434
35
3536
3637
3738
......
7677
7778
7879
80
81
82
83
84
85
86
7987
8088
8189
......
9098
9199
92100
101
102
103
104
105
106
93107
108
94109
95110
96111
......
145160
146161
147162
163
164
148165
149166
150167
......
153170
154171
155172
173
156174
157175
158176
......
163181
164182
165183
166
184
167185
168186
169187
......
225243
226244
227245
228
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
229277
230278
231279
......
234282
235283
236284
237
285
238286
239287
240288
289
241290
242291
292
243293
244294
245295
......
264314
265315
266316
267
317
318
319
320
321
322
323
324
325
326
327
328
268329
269330
270331
......
277338
278339
279340
341
342
343
280344
281345
282346
......
328392
329393
330394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
331418
332419
333420
334
421
335422
336423
337424
......
431518
432519
433520
434
435
521
522
523
436524
437525
438526
QPushButton* buttonOpen;
QGroupBox* staticAccount = new QGroupBox(_("Unresolved accounts"));
QGroupBox* staticCategory = new QGroupBox(_("Unresolved categories"));
QGroupBox* staticTag = new QGroupBox(_("Unresolved tags"));
_icons[KissPanel::LOW_RES_ICON] = IMPORT_LOW_ICON;
_icons[KissPanel::HIGH_RES_ICON] = IMPORT_ICON;
_categoriesGrid->setHorizontalHeaderLabels(labels);
_categoriesGrid->resizeColumnsToContents();
_tagsGrid = new QTableWidget(0, 3);
_tagsGrid->verticalHeader()->setHidden(true);
labels.clear();
labels << _("File tag") << _("Tag name") << _("Internal tag");
_tagsGrid->setHorizontalHeaderLabels(labels);
_tagsGrid->resizeColumnsToContents();
{
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(_accountsGrid);
staticCategory->setLayout(vbox);
}
{
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(_tagsGrid);
staticTag->setLayout(vbox);
}
vbox2->addWidget(staticCategory);
vbox2->addWidget(staticTag);
_operationsGrid = new GridAccount(kiss, this, false, false, false);
connect(_operationsGrid, SIGNAL(cellChanged(int, int)), this, SLOT(OnOperationModified(int, int)));
std::map<int, int> resolvedAccounts;
QString* userCategories;
std::map<int, int> resolvedCategories;
QString* userTags;
std::map<int, int> resolvedTags;
QTableWidgetItem* item;
QString path = _fileTxt->text();
_buttonIntegrate->setEnabled(false);
_accountsGrid->setRowCount(0);
_categoriesGrid->setRowCount(0);
_tagsGrid->setRowCount(0);
_operationsGrid->setRowCount(0);
_importEngine = _kiss->GetImportEngine(path);
return ;
}
_importEngine->ParseFile(_unresolvedAccounts, _unresolvedCategories);
_importEngine->ParseFile(_unresolvedAccounts, _unresolvedCategories, _unresolvedTags);
if (_unresolvedAccounts.size())
{
_categoriesGrid->layout();
}
if (!_unresolvedAccounts.size() && !_unresolvedCategories.size())
if (_unresolvedTags.size())
{
int nb_tags = user->GetTagsNumber();
userTags = new QString[nb_tags+1];
userTags[0] = _("Create one");
for(i=0; i<nb_tags; i++)
userTags[i+1] = user->_tags[i].name;
ChoiceDelegate* tagEditor = new ChoiceDelegate(this, userTags, nb_tags+1);
_tagsGrid->setItemDelegateForColumn(2, tagEditor);
_buttonLoadOperations->setEnabled(true);
_tagsGrid->setRowCount(_unresolvedTags.size());
for (i=0; i<(int)_unresolvedTags.size(); i++)
{
item = new QTableWidgetItem(_unresolvedTags[i].name);
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
_tagsGrid->setItem(i, 0, item);
_tagsGrid->setItem(i, 1, new QTableWidgetItem(""));
_tagsGrid->setItem(i, 2, new QTableWidgetItem(userTags[0]));
}
_tagsGrid->resizeColumnsToContents();
_tagsGrid->layout();
}
if (!_unresolvedAccounts.size() && !_unresolvedCategories.size() && !_unresolvedTags.size())
{
OnLoadOperations();
}
void ImportPanel::OnLoadOperations()
{
int i, nbAccounts=0, nbCategories=0;
int i, nbAccounts=0, nbCategories=0, nbTags=0;
User* user = _kiss->GetUser();
Account account;
Category category;
Tag tag;
std::map<int, int> accounts;
std::map<int, int> categories;
std::map<int, int> tags;
int oldid;
for(i=0; i<_accountsGrid->rowCount(); i++)
}
}
if (nbAccounts || nbCategories)
for(i=0; i<_tagsGrid->rowCount(); i++)
{
if (_tagsGrid->item(i, 2)->text() == _("Create one"))
nbTags++;
else
{
oldid = _unresolvedTags[i].id;
tags[oldid] = user->GetTagId(_tagsGrid->item(i, 2)->text());;
}
}
if (nbAccounts || nbCategories || nbTags)
{
QString message, v;
if (nbCategories)
message += v.sprintf(_("%d categories").toStdString().c_str(), nbCategories);
if (nbTags)
message += v.sprintf(_("%d tags").toStdString().c_str(), nbTags);
message += _(" will be created, is it ok ?");
if (QMessageBox::question(0, "KissCount", message, QMessageBox::Yes|QMessageBox::No) == QMessageBox::No)
_categoriesGrid->setRowCount(0);
for(i=0; i<_tagsGrid->rowCount(); i++)
{
if (_tagsGrid->item(i, 2)->text() == _("Create one"))
{
tag = _unresolvedTags[i] ;
if (_tagsGrid->item(i, 1)->text().length())
tag.name = _tagsGrid->item(i, 1)->text();
else
tag.name = _tagsGrid->item(i, 0)->text();
if (tag.name.length() == 0)
{
QMessageBox::critical(0, _("Error"), _("Tag ") + QString::number(i) + _(" must have a name"));
return;
}
oldid = tag.id;
tags[oldid] = tag.id = _kiss->AddTag(tag);
}
}
_tagsGrid->setRowCount(0);
_wxUI->NeedReload();
}
_operations = _importEngine->GetOperations(accounts, categories);
_operations = _importEngine->GetOperations(accounts, categories, tags);
if (_operations->size())
{
{
static bool update = false;
if (col != GridAccount::DESCRIPTION &&
col != GridAccount::CATEGORY &&
if (col != GridAccount::DESCRIPTION &&
col != GridAccount::CATEGORY &&
col != GridAccount::TAG &&
col != GridAccount::ACCOUNT)
return ;
src/view/ImportPanel.hpp
4848
4949
5050
51
51
5252
5353
5454
......
5858
5959
6060
61
6162
6263
64
6365
6466
6567
private:
QHBoxLayout *_hbox;
QTableWidget* _accountsGrid, *_categoriesGrid;
QTableWidget* _accountsGrid, *_categoriesGrid, *_tagsGrid;
QLineEdit* _fileTxt;
GridAccount* _operationsGrid;
ImportEngine* _importEngine;
std::vector<Account> _unresolvedAccounts;
std::vector<Category> _unresolvedCategories;
std::vector<Tag> _unresolvedTags;
std::map<int, int> _resolvedAccounts;
std::map<int, int> _resolvedCategories;
std::map<int, int> _resolvedTags;
void ProcessFile();
};
src/view/PreferencesPanel.cpp
2525
2626
2727
28
2829
2930
3031
3132
3233
3334
35
3436
35
37
3638
3739
3840
......
4951
5052
5153
54
5255
5356
5457
......
138141
139142
140143
141
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
142159
143160
144161
......
151168
152169
153170
154
171
155172
156173
157174
......
166183
167184
168185
169
186
170187
171188
189
172190
173191
174192
......
436454
437455
438456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
439526
440527
441528
......
722809
723810
724811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
725859
726860
727861
......
10801214
10811215
10821216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
10831299
10841300
10851301
enum {ACCOUNT_NAME, ACCOUNT_NUMBER, ACCOUNT_DEFAULT, ACCOUNT_VIRTUAL, ACCOUNT_BLOCKED, 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};
PreferencesPanel::PreferencesPanel(KissCount* kiss, wxUI *parent, bool lowResolution) : KissPanel(kiss, parent, lowResolution), _sharedWith(0), _curAccountRow(-1), _defaultSignalMapper(this), _virtualSignalMapper(this), _blockedSignalMapper(this), _deleteAccountSignalMapper(this), _deleteCategorySignalMapper(this), _backgroundColorSignalMapper(this), _foregroundColorSignalMapper(this), _fontSignalMapper(this), _inModification(false)
{
QVBoxLayout *vbox = new QVBoxLayout;
QHBoxLayout *hbox1 = new QHBoxLayout;
QHBoxLayout *hbox2 = new QHBoxLayout;
QHBoxLayout *hbox3 = new QHBoxLayout;
//QHBoxLayout *hbox = new QHBoxLayout;
QGroupBox* staticUser, *staticAccount, *staticCategories, *staticLanguage, *staticOperationOrder, *staticSharedWith;
QGroupBox* staticUser, *staticAccount, *staticCategories, *staticTags, *staticLanguage, *staticOperationOrder, *staticSharedWith;
User* user = _kiss->GetUser();
QGridLayout *gridBagSizer;
QLabel* label;
staticUser = new QGroupBox(_("User"));
staticAccount = new QGroupBox(_("Accounts"));
staticCategories = new QGroupBox(_("Categories"));
staticTags = new QGroupBox(_("Tags"));
staticLanguage = new QGroupBox(_("Language"));
staticOperationOrder = new QGroupBox(_("Operation order"));
staticSharedWith = new QGroupBox(_("Shared with"));
connect(_categoriesGrid, SIGNAL(cellChanged(int, int)), this, SLOT(OnCategoryModified(int, int)));
vbox->addWidget(staticCategories);
hbox2->addWidget(staticCategories);
// Tags
staticBoxSizer = new QVBoxLayout ();
staticTags->setLayout(staticBoxSizer);
_tagsGrid = new QTableWidget();
staticBoxSizer->addWidget(_tagsGrid);
InitTags(user);
connect(_tagsGrid, SIGNAL(cellChanged(int, int)), this, SLOT(OnTagModified(int, int)));
hbox2->addWidget(staticTags);
// Operation Order
staticBoxSizer = new QVBoxLayout ();
staticBoxSizer->addWidget(_operationOrder);
hbox2->addWidget(staticOperationOrder);
hbox3->addWidget(staticOperationOrder);
connect(_operationOrder, SIGNAL(currentIndexChanged(int)), this, SLOT(OnOperationOrderChange(int)));
staticBoxSizer->addWidget(_language);
hbox2->addWidget(staticLanguage);
hbox3->addWidget(staticLanguage);
vbox->addLayout(hbox2);
vbox->addLayout(hbox3);
connect(&_defaultSignalMapper, SIGNAL(mapped(int)), this, SLOT(OnAccountDefaultClicked(int)));
connect(&_virtualSignalMapper, SIGNAL(mapped(int)), this, SLOT(OnAccountVirtualClicked(int)));
}
}
#define SET_READ_ONLY_TAG(row, line) _tagsGrid->item(row, line)->setFlags(_tagsGrid->item(row, line)->flags() & ~Qt::ItemIsEditable);
void PreferencesPanel::InitTags(User* user)
{
std::vector<Tag>::iterator it;
int curLine = 0;
DEFAULT_FONT(font);
Tag tag;
_tagsGrid->setColumnCount(NUMBER_COLS_TAG);
_tagsGrid->verticalHeader()->setHidden(true);
_tagsGrid->setFont(font);
_tagsGrid->setHorizontalHeaderItem(TAG_NAME, new QTableWidgetItem(_("Name")));
_tagsGrid->setHorizontalHeaderItem(TAG_DELETE, new QTableWidgetItem(_("Delete")));
_tagsGrid->setRowCount(user->GetTagsNumber()+1);
font.setBold(true);
for(int i=0; i<NUMBER_COLS_TAG; i++)
{
_tagsGrid->horizontalHeaderItem(i)->setFont(font);
}
for (it=user->_tags.begin(); it!=user->_tags.end(); it++, curLine++)
{
AddTag(curLine, *it);
}
for(int i=0; i<NUMBER_COLS_TAG; i++)
if (!_tagsGrid->item(curLine, i))
_tagsGrid->setItem(curLine, i, new QTableWidgetItem(""));
SET_READ_ONLY_TAG(curLine, TAG_DELETE);
tag.id = 0;
AddTag(curLine, tag);
}
void PreferencesPanel::AddTag(int line, Tag tag)
{
QCheckBox* checkBox;
if (tag.id != 0)
{
_tagsGrid->setItem(line, TAG_NAME, new QTableWidgetItem(_(tag.name.toStdString().c_str())));
checkBox = new QCheckBox();
checkBox->setCheckState(Qt::Unchecked);
_tagsGrid->setCellWidget(line, TAG_DELETE, checkBox);
_deleteTagSignalMapper.setMapping(checkBox, tag.id);
connect(checkBox, SIGNAL(stateChanged(int)), &_deleteTagSignalMapper, SLOT(map()));
for(int i=0; i<NUMBER_COLS_TAG; i++)
if (_tagsGrid->item(line, i) == 0)
_tagsGrid->setItem(line, i, new QTableWidgetItem(""));
}
else
{
for(int i=0; i<NUMBER_COLS_TAG; i++)
if (!_tagsGrid->item(line, i))
_tagsGrid->setItem(line, i, new QTableWidgetItem(""));
SET_READ_ONLY_TAG(line, TAG_DELETE);
_tagsGrid->resizeColumnsToContents();
}
}
void PreferencesPanel::InitLanguage(User* user)
{
int i, select=0;
_inModification = false;
}
void PreferencesPanel::OnTagDeleteClicked(int id)
{
QStringList tags;
int i, row;
QString res;
User* user = _kiss->GetUser();
bool ok;
QCheckBox* checkBox = qobject_cast<QCheckBox*> (_deleteTagSignalMapper.mapping(id));
Tag tag;
std::vector<Tag>::iterator it;
if (_inModification) return;
it = std::find(user->_tags.begin(), user->_tags.end(), id);
if (it == user->_tags.end()) return ;
_inModification = true;
row = it-user->_tags.begin();
tag = user->_tags[row];
tags << _("None");
for(i=0; i < user->GetTagsNumber(); i++)
if (user->_tags[i].id != id)
tags << _(user->_tags[i].name.toStdString().c_str());
res = QInputDialog::getItem(0, "KissCount", _("Wich tag will replace this one ?"), tags, 0, false, &ok);
if (!ok)
{
checkBox->setCheckState(Qt::Unchecked);
_inModification = false;
return;
}
else
{
i = tags.indexOf(res);
_kiss->DeleteTag(tag, (!i) ? 0 : user->GetTagId(tags[i]));
_tagsGrid->removeRow(row);
_wxUI->NeedReload();
}
_inModification = false;
}
void PreferencesPanel::OnBackgroundColorClicked(int id)
{
User* user = _kiss->GetUser();
_inModification = false;
}
void PreferencesPanel::OnTagModified(int row, int col)
{
int op_complete = 1;
QString value;
User* user = _kiss->GetUser();
Tag new_tag, old_tag;
int new_id;
QTableWidgetItem* item = _tagsGrid->item(row, col);
if (_inModification) return;
_inModification = true;
value = item->text();
if (value.size())
{
new_tag.name = value;
op_complete--;
}
// Tags modification
if (user->GetTagsNumber() && row < user->GetTagsNumber())
{
old_tag = user->_tags[row];
new_tag.id = user->_tags[row].id;
if (new_tag.name.length() == 0)
{
QMessageBox::critical(0, _("Error"), _("Tag must have a name"));
_tagsGrid->setItem(row, TAG_NAME, new QTableWidgetItem(_(user->_tags[row].name.toStdString().c_str())));
_inModification = false;
return ;
}
try {
new_id = user->GetTagId(new_tag.name);
if (new_id != new_tag.id)
{
QMessageBox::critical(0, _("Error"), _("Tag ")+new_tag.name+_(" already exists"));
_tagsGrid->setItem(row, TAG_NAME, new QTableWidgetItem(_(user->_tags[row].name.toStdString().c_str())));
_inModification = false;
return ;
}
}
catch(User::TagNotFound e)
{}
_kiss->UpdateTag(new_tag);
}
// New tag
else
{
if (op_complete)
{
_inModification = false;
return ;
}
try {
user->GetTagId(new_tag.name);
QMessageBox::critical(0, _("Error"), _("Tag ")+new_tag.name+_(" already exists"));
_inModification = false;
return ;
}
catch(User::TagNotFound e)
{}
_kiss->AddTag(new_tag);
AddTag(row, new_tag);
SET_READ_ONLY_TAG(row, TAG_DELETE);
new_tag.id = 0;
_tagsGrid->setRowCount(row+2);
AddTag(++row, new_tag);
}
_wxUI->NeedReload();
_inModification = false;
}
void PreferencesPanel::OnChangeName()
{
User* user = _kiss->GetUser();
src/view/PreferencesPanel.hpp
4646
4747
4848
49
4950
5051
5152
......
5354
5455
5556
57
5658
5759
5860
......
6264
6365
6466
67
6568
6669
6770
6871
6972
7073
71
74
7275
7376
7477
78
7579
7680
7781
7882
7983
84
8085
8186
8287
void OnAccountDeleteClicked(int id);
void OnAccountHiddenClicked(int id);
void OnCategoryDeleteClicked(int id);
void OnTagDeleteClicked(int id);
void OnBackgroundColorClicked(int id);
void OnForegroundClicked(int id);
void OnFontClicked(int id);
void OnAccountCellChanged(int row, int col, int, int);
void OnSharedChange(QListWidgetItem *item);
void OnCategoryModified(int row, int col);
void OnTagModified(int row, int col);
void OnChangeName();
void OnChangePassword();
void OnOperationOrderChange(int index);
private:
QTableWidget* _accountsGrid;
QTableWidget* _categoriesGrid;
QTableWidget* _tagsGrid;
QLineEdit* _name;
QListWidget* _language;
QComboBox* _operationOrder;
QListWidget* _sharedWith;
int _curAccountRow;
std::map<QString, QString> _sharedOwners;
QSignalMapper _defaultSignalMapper, _virtualSignalMapper, _blockedSignalMapper, _deleteAccountSignalMapper, _hiddenAccountSignalMapper, _deleteCategorySignalMapper, _backgroundColorSignalMapper, _foregroundColorSignalMapper, _fontSignalMapper;
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);
void InitLanguage(User* user);
void InitOperationOrder(User* user);
void AddAccount(int line, Account ac);
void AddCategory(int line, Category cat);
void AddTag(int line, Tag tag);
};
#endif
src/view/SearchBanner.cpp
2525
2626
2727
28
2829
2930
3031
......
7475
7576
7677
78
79
80
81
82
83
84
85
86
87
7788
7889
7990
......
99110
100111
101112
113
102114
103115
104116
......
114126
115127
116128
117
118
119
120
129
130
131
132
133
134
121135
122136
123137
......
141155
142156
143157
144
158
145159
146160
147161
......
214228
215229
216230
231
232
233
234
217235
218236
219237
......
223241
224242
225243
226
244
227245
228246
229247
User* user = _kiss->GetUser();
std::vector<Account>::iterator accountIt;
std::vector<Category>::iterator categoryIt;
std::vector<Tag>::iterator tagIt;
QDate firstOfMonth = QDate::currentDate();
_checkDateFrom = new QCheckBox(_("Date from"));
}
_category->setMaximumSize(QSize(_category->contentsRect().width()*1.5, _category->sizeHint().height()));
_tag = new QListWidget(this);
item = new QListWidgetItem(_("Unknown"), _tag);
item->setCheckState (Qt::Unchecked);
for(tagIt = user->_tags.begin(); tagIt != user->_tags.end(); tagIt++)
{
item = new QListWidgetItem(_(tagIt->name.toStdString().c_str()), _tag);
item->setCheckState (Qt::Unchecked);
}
_tag->setMaximumSize(QSize(_tag->contentsRect().width()*1.5, _tag->sizeHint().height()));
_optype = new QListWidget(this);
item = new QListWidgetItem(_("Fix"), _optype);
item->setCheckState (Qt::Unchecked);
QLabel* labelAmountFrom = new QLabel(_("Amount from"));
QLabel* labelAmountTo = new QLabel(_("Amount to"));
QLabel* labelCategory = new QLabel(_("Category"));
QLabel* labelTag = new QLabel(_("Tag"));
QLabel* labelOperations = new QLabel(_("Operations"));
QLabel* labelAccount = new QLabel(_("Account"));
gridBagSizer->addWidget(_amountTo, 1, 4);
gridBagSizer->addWidget(labelCategory, 0, 5);
gridBagSizer->addWidget(_category, 1, 5);
gridBagSizer->addWidget(labelOperations, 0, 6);
gridBagSizer->addWidget(_optype, 1, 6);
gridBagSizer->addWidget(labelAccount, 0, 7);
gridBagSizer->addWidget(_account, 1, 7);
gridBagSizer->addWidget(labelTag, 0, 6);
gridBagSizer->addWidget(_tag, 1, 6);
gridBagSizer->addWidget(labelOperations, 0, 7);
gridBagSizer->addWidget(_optype, 1, 7);
gridBagSizer->addWidget(labelAccount, 0, 8);
gridBagSizer->addWidget(_account, 1, 8);
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
}
{
QString *description=0;
int *amountFrom=0, *amountTo=0;
std::vector<int> categories, accounts;
std::vector<int> categories, tags, accounts;
QDate *dateFrom=0, *dateTo=0;
User* user= _kiss->GetUser();
int i, types=0;
if (_category->item(i)->checkState() == Qt::Checked)
categories.push_back((i) ? user->_categories[i-1].id : 0);
for(i=0; i<user->GetTagsNumber()+1; i++)
if (_tag->item(i)->checkState() == Qt::Checked)
tags.push_back((i) ? user->_tags[i-1].id : 0);
types |= (_optype->item(0)->checkState() == Qt::Checked) ? Database::FIX_OP : 0;
types |= (_optype->item(1)->checkState() == Qt::Checked) ? Database::NON_FIX_OP : 0;
types |= (_optype->item(2)->checkState() == Qt::Checked) ? Database::CHECKED_OP : 0;
if (_account->item(i)->checkState() == Qt::Checked)
accounts.push_back((i) ? user->_accounts[i-1].id : 0);
_operations = _kiss->Search(description, dateFrom, dateTo, amountFrom, amountTo, categories, types, accounts);
_operations = _kiss->Search(description, dateFrom, dateTo, amountFrom, amountTo, categories, types, accounts, tags);
end:
delete dateFrom;
src/view/SearchBanner.hpp
5151
5252
5353
54
54
5555
5656
5757
QCalendarWidget* _calendarFrom, *_calendarTo;
QCheckBox *_checkDateFrom, *_checkDateTo;
QLineEdit* _description, *_amountFrom, *_amountTo;
QListWidget* _category, *_account, *_optype;
QListWidget* _category, *_tag, *_account, *_optype;
};
#endif
src/view/StatsPanel.cpp
147147
148148
149149
150
150151
151152
152153
......
173174
174175
175176
176
177
177178
178179
179180
......
197198
198199
199200
200
201
201202
202203
203204
{
std::map<int, std::map<int, std::map<int, int> > > accountAmounts;
std::map<int, int> categories;
std::map<int, int> tags;
std::map<int, std::vector<int> > operations;
std::vector<Account>::iterator accountIt;
std::map<int, int>::iterator categoriesIt;
date.setDate(yearFrom, monthFrom+1, 1);
nbDays = date.daysInMonth();
_kiss->GetMonthStats(monthFrom, yearFrom, nbDays, &operations, &categories);
_kiss->GetMonthStats(monthFrom, yearFrom, nbDays, &operations, &categories, &tags);
// Line on 0 all over the years
for (a=0; a<nbDays; a++)
}
else
{
_kiss->GetStats(monthFrom, yearFrom, monthTo, yearTo, &accountAmounts, &categories);
_kiss->GetStats(monthFrom, yearFrom, monthTo, yearTo, &accountAmounts, &categories, &tags);
// Line on 0 all over the years
nbDays = ((yearTo - yearFrom) + 1) * 12;
src/view/grid/ChoiceDelegate.hpp
3838
3939
4040
41
4142
4243
4344
private:
QString* _values;
int _nbValues;
bool _editable;
};
#endif
src/view/grid/GridAccount.cpp
5757
5858
5959
60
6061
6162
6263
......
7071
7172
7273
73
74
7475
7576
7677
......
119120
120121
121122
123
124
125
126
127
128
129
130
122131
123132
133
124134
125135
126136
......
136146
137147
138148
149
139150
140151
141152
......
234245
235246
236247
248
249
250
251
237252
238253
239254
......
281296
282297
283298
299
284300
285301
286302
......
341357
342358
343359
360
344361
345362
346363
......
366383
367384
368385
386
369387
370388
371389
......
386404
387405
388406
407
408
389409
390410
391411
......
487507
488508
489509
510
490511
491512
492513
......
896917
897918
898919
920
899921
900922
901923
......
914936
915937
916938
939
917940
918941
919942
......
954977
955978
956979
980
981
982
957983
958984
959985
......
9981024
9991025
10001026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
10011041
10021042
10031043
......
10521092
10531093
10541094
1055
1095
10561096
10571097
10581098
......
10951135
10961136
10971137
1138
1139
10981140
10991141
11001142
......
11331175
11341176
11351177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
11361191
11371192
11381193
11391194
11401195
11411196
1197
1198
1199
11421200
11431201
11441202
......
12241282
12251283
12261284
1285
12271286
12281287
12291288
User* user = _kiss->GetUser();
std::vector<Account>::iterator accountIt;
std::vector<Category>::iterator categoryIt;
std::vector<Tag>::iterator tagIt;
QTableWidgetItem* item;
QLabel* label;
setFont(font);
font.setBold(true);
QString colsName[] = {"", _("Description"), _("Date"), _("Debit"), _("Credit"), _("Category"), _("Account"), "", ""};
QString colsName[] = {"", _("Description"), _("Date"), _("Debit"), _("Credit"), _("Category"), _("Tag"), _("Account"), "", ""};
for(i=0; i<NUMBER_COLS_OPS; i++)
{
item = new QTableWidgetItem(colsName[i]);
_categories[i] = _(categoryIt->name.toStdString().c_str()) ;
}
_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()) ;
}
resizeColumnToContents(TREE);
resizeColumnToContents(CATEGORY);
resizeColumnToContents(TAG);
resizeColumnToContents(OP_DATE);
resizeColumnToContents(ACCOUNT);
resizeColumnToContents(OP_DELETE);
GridAccount::~GridAccount()
{
delete[] _categories;
delete[] _tags;
delete[] _accounts;
if (_completer)
delete _completer;
ChoiceDelegate* categoryEditor = new ChoiceDelegate(this, _categories, user->GetCategoriesNumber()-1);
setItemDelegateForColumn(CATEGORY, categoryEditor);
ChoiceDelegate* tagEditor = new ChoiceDelegate(this, _tags, user->GetTagsNumber());
setItemDelegateForColumn(TAG, tagEditor);
ChoiceDelegate* accountEditor = new ChoiceDelegate(this, _accounts, _nbAccounts);
setItemDelegateForColumn(ACCOUNT, accountEditor);
}
resizeColumnToContents(TREE);
resizeColumnToContents(TAG);
resizeColumnToContents(CATEGORY);
resizeColumnToContents(OP_DATE);
resizeColumnToContents(ACCOUNT);
QString description, v;
DEFAULT_FONT(font);
Category cat ;
Tag tag;
Operation op2;
QTableWidgetItem* item;
QCheckBox* checkBox;
if (op.id)
{
cat = user->GetCategory(op.category);
tag = user->GetTag(op.tag);
description = op.description;
UNESCAPE_CHARS(description);
setItem(line, ACCOUNT, new QTableWidgetItem(user->GetAccountName(op.account)));
if (!fix && !op.meta)
setItem(line, CATEGORY, new QTableWidgetItem(_(cat.name.toStdString().c_str())));
setItem(line, TAG, new QTableWidgetItem(_(tag.name.toStdString().c_str())));
checkBox = new QCheckBox();
checkBox->setCheckState(Qt::Unchecked);
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, TAG));
SET_READ_ONLY(this->item(line, ACCOUNT));
}
else
Operation op, op2, parent;
QFont font;
Category cat ;
Tag tag;
bool fix_cost;
Operation NULLop;
new_op.amount = 0.0;
new_op.description = "";
new_op.category = 0;
new_op.tag = 0;
new_op.fix_cost = false;
new_op.account = 0;
new_op.checked = 0;
if (!item(row, CATEGORY)->text().length())
setItem(row, CATEGORY, new QTableWidgetItem(_(user->GetCategoryName(op_tmp.category).toStdString().c_str())));
if (!item(row, TAG)->text().length() && op_tmp.tag)
setItem(row, TAG, new QTableWidgetItem(_(user->GetTagName(op_tmp.tag).toStdString().c_str())));
if (!item(row, ACCOUNT)->text().length())
setItem(row, ACCOUNT, new QTableWidgetItem(user->GetAccountName(op_tmp.account)));
op_complete--;
}
value = item(row, TAG)->text();
if (value.length())
{
try
{
new_op.tag = user->GetTagId(value);
}
catch (User::TagNotFound e)
{
op_complete++;
}
op_complete--;
}
value = item(row, ACCOUNT)->text();
if (value.length())
{
CheckOperation(new_op, row, new_op.checked, true);
SET_ROW_FONT(row, user->GetCategoryFont(cat.id));
if (op_complete) {
if (op_complete > 0) {
_inModification = false ;
return ;
}
Operation op ;
int category = 0;
bool updateCat = false ;
int tag = 0;
bool updateTag = false ;
bool openMeta;
if (!meta.childs.size()) return ;
if (op.category && op.category != category)
updateCat = false;
}
if (!tag)
{
if (op.tag)
{
tag = op.tag;
updateCat = true;
}
}
else
{
if (op.tag && op.tag != tag)
updateCat = false;
}
op.parent = meta.id;
}
if (updateCat)
meta.category = category;
if (updateTag)
meta.tag = tag;
meta.amount = _kiss->MetaAmount(meta.id);
UpdateOperation(meta);
op.amount = 0;
op.description = "";
op.category = 0;
op.tag = 0;
op.fix_cost = fix;
op.account = 0;
op.checked = false;
src/view/grid/GridAccount.hpp
4242
4343
4444
45
45
4646
4747
4848
......
7777
7878
7979
80
80
8181
8282
8383
public:
class OperationNotFound {};
enum {TREE, DESCRIPTION, OP_DATE, DEBIT, CREDIT, CATEGORY, ACCOUNT, OP_DELETE, CHECKED, NUMBER_COLS_OPS};
enum {TREE, DESCRIPTION, OP_DATE, DEBIT, CREDIT, CATEGORY, TAG, ACCOUNT, OP_DELETE, CHECKED, NUMBER_COLS_OPS};
GridAccount(KissCount* kiss, QWidget *parent,
bool canAddOperation, bool setWeek, bool synchronizeWithDatabase);
bool _displayLines;
bool _setWeek;
bool _databaseSynchronization;
QString* _categories, *_accounts;
QString* _categories, *_accounts, *_tags;
int _nbAccounts;
std::vector<Operation>* _operations;
bool _loadOperations;

Archive Download the corresponding diff file