1 /***************************************************************************
2 * SPDX-FileCopyrightText: 2021 S. MANKOWSKI stephane@mankowski.fr
3 * SPDX-FileCopyrightText: 2021 G. DE BURE support@mankowski.fr
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 ***************************************************************************/
6 /** @file
7 * This file defines classes SKGObjectModel.
8 *
9 * @author Stephane MANKOWSKI / Guillaume DE BURE
10 */
11 #include "skgobjectmodel.h"
12
13 #include <math.h>
14
15 #include <kconfiggroup.h>
16 #include <klocalizedstring.h>
17
18 #include <qapplication.h>
19 #include <qcolor.h>
20 #include <qdir.h>
21 #include <qfont.h>
22 #include <qicon.h>
23 #include <qmimedata.h>
24 #include <qstandardpaths.h>
25
26 #include "skgaccountobject.h"
27 #include "skgbudgetobject.h"
28 #include "skgbudgetruleobject.h"
29 #include "skgcategoryobject.h"
30 #include "skgdocumentbank.h"
31 #include "skgmainpanel.h"
32 #include "skgoperationobject.h"
33 #include "skgpayeeobject.h"
34 #include "skgrecurrentoperationobject.h"
35 #include "skgsuboperationobject.h"
36 #include "skgtraces.h"
37 #include "skgtrackerobject.h"
38 #include "skgtransactionmng.h"
39 #include "skgunitobject.h"
40 #include "skgunitvalueobject.h"
41
42 SKGObjectModel::
SKGObjectModel(SKGDocumentBank * iDocument,const QString & iTable,const QString & iWhereClause,QWidget * iParent,const QString & iParentAttribute,bool iResetOnCreation)43 SKGObjectModel(SKGDocumentBank* iDocument,
44 const QString& iTable,
45 const QString& iWhereClause,
46 QWidget* iParent,
47 const QString& iParentAttribute,
48 bool iResetOnCreation)
49 : SKGObjectModelBase(iDocument, iTable, iWhereClause, iParent, iParentAttribute, false)
50 {
51 SKGTRACEINFUNC(1)
52
53 m_operationTable = false;
54 m_recurrentoperationTable = false;
55 m_trackerTable = false;
56 m_accountTable = false;
57 m_unitTable = false;
58 m_unitvalueTable = false;
59 m_suboperationTable = false;
60 m_categoryTable = false;
61 m_ruleTable = false;
62 m_interestTable = false;
63 m_interestResultTable = false;
64 m_payeeTable = false;
65 m_budgetTable = false;
66 m_budgetRuleTable = false;
67 m_isResetRealyNeeded = iResetOnCreation;
68 refresh();
69 }
70
buidCache()71 void SKGObjectModel::buidCache()
72 {
73 SKGObjectModelBase::buidCache();
74 m_operationTable = (getRealTable() == QStringLiteral("operation") || getRealTable() == QStringLiteral("suboperation"));
75 m_payeeTable = (getRealTable() == QStringLiteral("payee"));
76 m_trackerTable = (getRealTable() == QStringLiteral("refund"));
77 m_recurrentoperationTable = (getRealTable() == QStringLiteral("recurrentoperation"));
78 m_accountTable = (getRealTable() == QStringLiteral("account"));
79 m_unitTable = (getRealTable() == QStringLiteral("unit"));
80 m_unitvalueTable = (getRealTable() == QStringLiteral("unitvalue"));
81 m_suboperationTable = (getTable() == QStringLiteral("v_suboperation_consolidated"));
82 m_ruleTable = (getRealTable() == QStringLiteral("rule"));
83 m_categoryTable = (getRealTable() == QStringLiteral("category"));
84 m_interestTable = (getRealTable() == QStringLiteral("interest"));
85 m_interestResultTable = (getRealTable() == QStringLiteral("interest_result"));
86 m_budgetTable = (getRealTable() == QStringLiteral("budget"));
87 m_budgetRuleTable = (getRealTable() == QStringLiteral("budgetrule"));
88
89 if (m_unitvalueTable) {
90 SKGUnitValueObject unitValObject(getObject(this->index(0, 0)));
91 SKGUnitObject unitObject;
92 unitValObject.getUnit(unitObject);
93 SKGUnitObject parentUnit;
94 unitObject.getUnit(parentUnit);
95 if (parentUnit.exist()) {
96 m_cacheUnit.Name = parentUnit.getName();
97 m_cacheUnit.Symbol = parentUnit.getSymbol();
98 m_cacheUnit.Value = 1;
99 m_cacheUnit.NbDecimal = unitObject.getNumberDecimal();
100 } else {
101 m_cacheUnit.Name = QLatin1String("");
102 m_cacheUnit.Symbol = QLatin1String("");
103 m_cacheUnit.Value = 1;
104 m_cacheUnit.NbDecimal = unitObject.getNumberDecimal();
105 }
106 if (m_cacheUnit.Symbol.isEmpty()) {
107 m_cacheUnit.Symbol = ' ';
108 }
109
110 // Bug 209672 vvvv
111 if (unitObject.getType() == SKGUnitObject::INDEX) {
112 m_cacheUnit.Symbol = ' ';
113 m_cacheUnit.Name = ' ';
114 }
115 // Bug 209672 ^^^^
116 }
117
118 if (m_operationTable) {
119 // Read Setting
120 KSharedConfigPtr config = KSharedConfig::openConfig();
121 KConfigGroup pref = config->group("skrooge_operation");
122 m_fontFutureOperationsColor = QVariant::fromValue(pref.readEntry("fontFutureColor", QColor(Qt::gray)));
123 m_fontNotValidatedOperationsColor = QVariant::fromValue(pref.readEntry("fontNotValidatedColor", QColor(Qt::blue)));
124 m_fontSubOperationsColor = QVariant::fromValue(pref.readEntry("fontSubOperationColor", QColor(Qt::darkGreen)));
125 }
126
127 if (m_recurrentoperationTable) {
128 // Read Setting
129 KSharedConfigPtr config = KSharedConfig::openConfig();
130 KConfigGroup pref = config->group("skrooge_scheduled");
131 m_fontDisabledScheduleColor = QVariant::fromValue(pref.readEntry("fontFutureColor", QColor(Qt::gray)));
132 }
133
134 m_iconFavorite = SKGServices::fromTheme(QStringLiteral("bookmarks"));
135
136 if (m_operationTable || m_recurrentoperationTable) {
137 m_iconTransfer = SKGServices::fromTheme(QStringLiteral("exchange-positions"));
138 QStringList overlays;
139 overlays.push_back(QStringLiteral("list-remove"));
140 m_iconGroup = SKGServices::fromTheme(QStringLiteral("exchange-positions"), overlays);
141 m_iconSplit = SKGServices::fromTheme(QStringLiteral("split"));
142 m_iconImported = SKGServices::fromTheme(QStringLiteral("utilities-file-archiver"));
143 {
144 QStringList overlay;
145 overlay.push_back(QStringLiteral("dialog-ok"));
146 m_iconImportedChecked = SKGServices::fromTheme(QStringLiteral("utilities-file-archiver"), overlay);
147 }
148
149 m_iconRecurrent = SKGServices::fromTheme(QStringLiteral("chronometer"));
150 {
151 QStringList overlay;
152 overlay.push_back(QStringLiteral("bookmarks"));
153 m_iconRecurrentMaster = SKGServices::fromTheme(QStringLiteral("chronometer"), overlay);
154 }
155 }
156
157 if (m_budgetTable) {
158 m_iconGreen = SKGServices::fromTheme(QStringLiteral("security-high"));
159 m_iconRed = SKGServices::fromTheme(QStringLiteral("security-low"));
160 m_iconAnber = SKGServices::fromTheme(QStringLiteral("security-medium"));
161 }
162
163 if (m_unitTable) {
164 m_iconMuchMore = SKGServices::fromTheme(QStringLiteral("skrooge_much_more"));
165 m_iconMuchLess = SKGServices::fromTheme(QStringLiteral("skrooge_much_less"));
166 m_iconMore = SKGServices::fromTheme(QStringLiteral("skrooge_more"));
167 m_iconLess = SKGServices::fromTheme(QStringLiteral("skrooge_less"));
168 }
169
170 if (m_ruleTable) {
171 m_iconSearch = SKGServices::fromTheme(QStringLiteral("edit-find"));
172 m_iconUpdate = SKGServices::fromTheme(QStringLiteral("view-refresh"));
173 m_iconAlarm = SKGServices::fromTheme(QStringLiteral("dialog-warning"));
174 m_iconTemplate = SKGServices::fromTheme(QStringLiteral("edit-guides"));
175 }
176 m_iconClosed = SKGServices::fromTheme(QStringLiteral("dialog-close"));
177
178 if (m_categoryTable) {
179 m_iconCategory = SKGServices::fromTheme(QStringLiteral("view-categories"));
180 m_iconCategoryMoins = SKGServices::fromTheme(QStringLiteral("view-categories-expenditures"));
181 m_iconCategoryPlus = SKGServices::fromTheme(QStringLiteral("view-categories-incomes"));
182 }
183 }
184
~SKGObjectModel()185 SKGObjectModel::~SKGObjectModel()
186 {
187 SKGTRACEINFUNC(1)
188 }
189
headerData(int section,Qt::Orientation orientation,int role) const190 QVariant SKGObjectModel::headerData(int section, Qt::Orientation orientation, int role) const
191 {
192 _SKGTRACEINFUNC(10)
193
194 if (orientation == Qt::Horizontal) {
195 if (role == Qt::DisplayRole || role == Qt::ToolTipRole) {
196 QString att;
197 if (section >= 0 && section < m_listAttibutes.count()) {
198 att = m_listAttibutes[section];
199 } else {
200 att = SKGServices::intToString(section);
201 }
202
203 if (att == QStringLiteral("t_bookmarked") || att == QStringLiteral("i_NBRECURRENT") || att == QStringLiteral("t_status") || att == QStringLiteral("t_close") || att == QStringLiteral("t_imported")) {
204 return (role == Qt::ToolTipRole) ? SKGObjectModelBase::headerData(section, orientation, Qt::DisplayRole) : "";
205 }
206 }
207 }
208 return SKGObjectModelBase::headerData(section, orientation, role);
209 }
210
getAttributeForGrouping(const SKGObjectBase & iObject,const QString & iAttribute) const211 QString SKGObjectModel::getAttributeForGrouping(const SKGObjectBase& iObject, const QString& iAttribute) const
212 {
213 if (m_recurrentoperationTable && iAttribute == QStringLiteral("i_nb_times")) {
214 if (iObject.getAttribute(QStringLiteral("t_times")) != QStringLiteral("Y")) {
215 return QChar(8734);
216 }
217 } else if (m_ruleTable && iAttribute == QStringLiteral("t_action_type")) {
218 QString val = iObject.getAttribute(iAttribute);
219 if (val == QStringLiteral("S")) {
220 val = i18nc("Noun, a search", "Search");
221 } else if (val == QStringLiteral("U")) {
222 val = i18nc("Noun, a modification", "Update");
223 } else {
224 val = i18nc("Noun, an alarm", "Alarm");
225 }
226 return val;
227 } else if (iAttribute == QStringLiteral("t_bookmarked") || iAttribute == QStringLiteral("t_close")) {
228 QString val = iObject.getAttribute(iAttribute);
229 return val == QStringLiteral("Y") ? i18n("Yes") : i18n("No");
230 } else if (iAttribute == QStringLiteral("t_status")) {
231 QString val = iObject.getAttribute(iAttribute);
232 return val == QStringLiteral("N") ? i18n("None") : val == QStringLiteral("P") ? i18n("Pointed") : i18n("Checked");
233 }
234 return SKGObjectModelBase::getAttributeForGrouping(iObject, iAttribute);
235 }
236
computeData(const QModelIndex & iIndex,int iRole) const237 QVariant SKGObjectModel::computeData(const QModelIndex& iIndex, int iRole) const
238 {
239 if (!iIndex.isValid()) {
240 return QVariant();
241 }
242 _SKGTRACEINFUNC(10)
243 SKGObjectBase* obj = getObjectPointer(iIndex);
244 if (obj == nullptr || obj->getTable().isEmpty()) {
245 return SKGObjectModelBase::computeData(iIndex, iRole);
246 }
247
248 switch (iRole) {
249 case Qt::DisplayRole:
250 case Qt::EditRole:
251 case Qt::UserRole: {
252 QString att = m_listAttibutes[iIndex.column()];
253 QString val = obj->getAttribute(att);
254 if (att == QStringLiteral("i_NBRECURRENT")) {
255 if (iRole == Qt::UserRole) {
256 if (val != QStringLiteral("0")) {
257 return QLatin1String("Y");
258 }
259 if (obj->getAttribute(QStringLiteral("r_recurrentoperation_id")) != QStringLiteral("0")) {
260 return QLatin1String("Y");
261 }
262 return QLatin1String("N");
263 }
264 return "";
265 }
266 if (att == QStringLiteral("t_bookmarked") ||
267 att == QStringLiteral("t_status") ||
268 att == QStringLiteral("t_imported") ||
269 att == QStringLiteral("t_close") ||
270 att == QStringLiteral("t_action_type")
271 ) {
272 if (iRole == Qt::UserRole) {
273 if (m_ruleTable && att == QStringLiteral("t_action_type")) {
274 if (val == QStringLiteral("S")) {
275 return i18nc("Noun, a search", "Search");
276 }
277 if (val == QStringLiteral("U")) {
278 return i18nc("Noun, a modification", "Update");
279 }
280 return i18nc("Noun, an alarm", "Alarm");
281 }
282 return val;
283 }
284 return "";
285 }
286 if (m_interestTable && att == QStringLiteral("t_expenditure_value_date_mode")) {
287 if (val == QStringLiteral("0")) {
288 return i18nc("Noun", "Day -0");
289 }
290 if (val == QStringLiteral("1")) {
291 return i18nc("Noun", "Day -1");
292 }
293 if (val == QStringLiteral("2")) {
294 return i18nc("Noun", "Day -2");
295 }
296 if (val == QStringLiteral("3")) {
297 return i18nc("Noun", "Day -3");
298 }
299 if (val == QStringLiteral("4")) {
300 return i18nc("Noun", "Day -4");
301 }
302 if (val == QStringLiteral("5")) {
303 return i18nc("Noun", "Day -5");
304 }
305 return i18nc("Noun", "Fifteen");
306 }
307 if (m_accountTable && att == QStringLiteral("d_reconciliationdate")) {
308 if (val.isEmpty() && iRole == Qt::DisplayRole) {
309 return i18nc("Noun", "Never");
310 }
311 } else if (m_interestTable && att == QStringLiteral("t_income_value_date_mode")) {
312 if (val == QStringLiteral("0")) {
313 return i18nc("Noun", "Day +0");
314 }
315 if (val == QStringLiteral("1")) {
316 return i18nc("Noun", "Day +1");
317 }
318 if (val == QStringLiteral("2")) {
319 return i18nc("Noun", "Day +2");
320 }
321 if (val == QStringLiteral("3")) {
322 return i18nc("Noun", "Day +3");
323 }
324 if (val == QStringLiteral("4")) {
325 return i18nc("Noun", "Day +4");
326 }
327 if (val == QStringLiteral("5")) {
328 return i18nc("Noun", "Day +5");
329 }
330 return i18nc("Noun", "Fifteen");
331 }
332 if (getAttributeType(iIndex.column()) == SKGServices::FLOAT) {
333 double dval = SKGServices::stringToDouble(val);
334 if (iRole == Qt::DisplayRole) {
335 if (val.isEmpty()) {
336 return "";
337 }
338 if (att.endsWith(QLatin1String("_INCOME")) ||
339 att.endsWith(QLatin1String("_EXPENSE")) ||
340 (m_operationTable && obj->getAttribute(QStringLiteral("t_template")) == QStringLiteral("Y")) ||
341 (m_categoryTable && (att == QStringLiteral("f_REALCURRENTAMOUNT") ||
342 att == QStringLiteral("f_SUMCURRENTAMOUNT")))) {
343 if (dval == 0) {
344 return "";
345 }
346 }
347
348 SKGServices::SKGUnitInfo unit;
349 unit.Symbol = QLatin1String("");
350 unit.NbDecimal = 2;
351 if (!att.contains(QStringLiteral("QUANTITY")) && !att.contains(QStringLiteral("f_BALANCE_ENTERED"))) {
352 unit = qobject_cast<SKGDocumentBank*>(getDocument())->getPrimaryUnit();
353 if (m_unitvalueTable && !m_cacheUnit.Symbol.isEmpty()) {
354 unit = m_cacheUnit;
355 }
356 } else {
357 unit.NbDecimal = SKGServices::stringToInt(obj->getAttribute(QStringLiteral("i_NBDEC")));
358 if (unit.NbDecimal == 0) {
359 unit.NbDecimal = 2;
360 }
361 if (att != QStringLiteral("f_QUANTITYOWNED")) {
362 unit.Symbol = obj->getAttribute(QStringLiteral("t_UNIT"));
363 }
364 }
365
366 // Bug 209672 vvvv
367 if (m_unitTable) {
368 if (obj->getAttribute(QStringLiteral("t_type")) == QStringLiteral("I")) {
369 unit.Symbol = ' ';
370 }
371 }
372 // Bug 209672 ^^^
373
374 if (QString::compare(att, QStringLiteral("f_rate"), Qt::CaseInsensitive) == 0) {
375 unit.Symbol = '%';
376 unit.NbDecimal = 2;
377 } else if (att == QStringLiteral("f_coef")) {
378 unit.Symbol = QLatin1String("");
379 unit.NbDecimal = 2;
380 }
381
382 if (unit.Symbol.isEmpty()) {
383 unit.Symbol = ' ';
384 }
385
386 return SKGServices::toCurrencyString(dval, unit.Symbol, unit.NbDecimal);
387 }
388 return dval;
389 }
390 if (getAttributeType(iIndex.column()) == SKGServices::INTEGER) {
391 if (m_recurrentoperationTable && att == QStringLiteral("i_nb_times")) {
392 QString t_times = obj->getAttribute(QStringLiteral("t_times"));
393 if (t_times != QStringLiteral("Y")) {
394 return QChar(8734);
395 }
396 } else if ((att == QStringLiteral("i_NBOPERATIONS") || att == QStringLiteral("i_SUMNBOPERATIONS")) && val == QStringLiteral("0")) {
397 return "";
398 }
399
400 return SKGServices::stringToInt(val);
401 }
402 if (m_suboperationTable && att.startsWith(QLatin1String("p_"))) {
403 val = obj->getProperty(att.right(att.count() - 2));
404 if (val.isEmpty()) {
405 val = obj->getDocument()->getParameter(att.right(att.count() - 2), obj->getAttribute(QStringLiteral("i_OPID")) % "-operation");
406 }
407 return val;
408 }
409 if (m_payeeTable && att == QStringLiteral("t_CATEGORY") && val.isEmpty()) {
410 auto c = qobject_cast<SKGDocumentBank*>(getDocument())->getCategoryForPayee(obj->getAttribute(QStringLiteral("t_name")));
411 if (!c.isEmpty()) {
412 return i18n("Auto: %1", c);
413 }
414 }
415 break;
416 }
417 case Qt::DecorationRole: {
418 // decoration
419 QString att = m_listAttibutes[iIndex.column()];
420 if (att == QStringLiteral("t_bookmarked")) {
421 if (obj->getAttribute(QStringLiteral("t_bookmarked")) == QStringLiteral("Y")) {
422 return m_iconFavorite;
423 }
424 } else if (m_operationTable || m_recurrentoperationTable) {
425 if (att == QStringLiteral("t_mode")) {
426 if (obj->getAttribute(QStringLiteral("t_TRANSFER")) == QStringLiteral("Y")) {
427 return m_iconTransfer;
428 }
429 if (obj->getAttribute(QStringLiteral("i_group_id")) != QStringLiteral("0")) {
430 return m_iconGroup;
431 }
432 } else if (att == QStringLiteral("t_CATEGORY")) {
433 if (SKGServices::stringToInt(obj->getAttribute(QStringLiteral("i_NBSUBOPERATIONS"))) > 1) {
434 return m_iconSplit;
435 }
436 } else if (att == QStringLiteral("i_NBRECURRENT") && m_operationTable) {
437 if (obj->getAttribute(QStringLiteral("i_NBRECURRENT")) != QStringLiteral("0")) {
438 return m_iconRecurrentMaster;
439 }
440 if (obj->getAttribute(QStringLiteral("r_recurrentoperation_id")) != QStringLiteral("0")) {
441 return m_iconRecurrent;
442 }
443 } else if (att == QStringLiteral("t_imported")) {
444 QString impStatus = obj->getAttribute(QStringLiteral("t_imported"));
445 if (impStatus == QStringLiteral("Y")) {
446 return m_iconImported;
447 }
448 if (impStatus == QStringLiteral("P")) {
449 return m_iconImportedChecked;
450 }
451 } else if (att == QStringLiteral("t_REFUND") || att == QStringLiteral("t_REALREFUND") || att == QStringLiteral("t_REFUNDDISPLAY")) {
452 if (att == QStringLiteral("t_REFUNDDISPLAY")) {
453 if (obj->getAttribute(att).count(QStringLiteral("(")) > 1) {
454 att.clear();
455 } else {
456 att = QStringLiteral("t_REFUND");
457 }
458 }
459 if (!att.isEmpty()) {
460 QString trackerName;
461 trackerName = obj->getAttribute(att);
462 if (!trackerName.isEmpty()) {
463 SKGTrackerObject tracker(SKGObjectBase(getDocument(), QStringLiteral("refund"))); // Better performance if v_refund is not used
464 tracker.setName(trackerName);
465 tracker.load();
466
467 if (tracker.isClosed()) {
468 return m_iconClosed;
469 }
470 }
471 }
472 }
473 } else if (m_ruleTable) {
474 if (att == QStringLiteral("t_action_type")) {
475 QString val = obj->getAttribute(att);
476 if (val == QStringLiteral("S")) {
477 return m_iconSearch;
478 }
479 if (val == QStringLiteral("U")) {
480 return m_iconUpdate;
481 }
482 if (val == QStringLiteral("T")) {
483 return m_iconTemplate;
484 }
485 return m_iconAlarm;
486 }
487 } else if (m_unitTable) {
488 if (att == QStringLiteral("f_CURRENTAMOUNT")) {
489 SKGUnitObject unit(*obj);
490 double amountOneYearBefore = unit.getAmount(QDate::currentDate().addYears(-1));
491 double annualchange = 100.0 * (unit.getAmount() - amountOneYearBefore) / amountOneYearBefore;
492 if (annualchange >= 15) {
493 return m_iconMuchMore;
494 }
495 if (annualchange <= -15) {
496 return m_iconMuchLess;
497 }
498 if (annualchange >= 5) {
499 return m_iconMore;
500 }
501 if (annualchange <= -5) {
502 return m_iconLess;
503 }
504 }
505 } else if (m_accountTable) {
506 if (att == QStringLiteral("t_BANK")) {
507 QString t_icon = obj->getAttribute(QStringLiteral("t_icon"));
508 if (t_icon.isEmpty()) {
509 t_icon = obj->getAttribute(QStringLiteral("t_ICON"));
510 }
511 if (!t_icon.isEmpty()) {
512 QString fileName = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "skrooge/images/logo/" % t_icon);
513 if (fileName.isEmpty()) {
514 fileName = t_icon;
515 }
516 return QVariant::fromValue(QIcon(fileName));
517 }
518 } else if (att == QStringLiteral("f_importbalance")) {
519 QString val = obj->getAttribute(att);
520 if (val.isEmpty()) {
521 return "";
522 }
523
524 // Compute value
525 SKGAccountObject act(*obj);
526 auto soluces = act.getPossibleReconciliations(SKGServices::stringToDouble(val), false);
527 return SKGServices::fromTheme(soluces.isEmpty() ? QStringLiteral("security-low") : QStringLiteral("security-high"));
528 } else if (att == QStringLiteral("f_reconciliationbalance")) {
529 QString val = obj->getAttribute(att);
530 if (val.isEmpty()) {
531 return "";
532 }
533
534 // Compute value
535 SKGAccountObject act(*obj);
536 auto soluces = act.getPossibleReconciliations(SKGServices::stringToDouble(val), false);
537 return SKGServices::fromTheme(soluces.isEmpty() ? QStringLiteral("security-low") : QStringLiteral("security-high"));
538 }
539 } else if (m_categoryTable) {
540 if (iIndex.column() == 0) {
541 QString t_TYPEEXPENSE = obj->getAttribute(QStringLiteral("t_TYPEEXPENSE"));
542 if (t_TYPEEXPENSE == QStringLiteral("-")) {
543 return m_iconCategoryMoins;
544 }
545 if (t_TYPEEXPENSE == QStringLiteral("+")) {
546 return m_iconCategoryPlus;
547 }
548 return m_iconCategory;
549 }
550 } else if (m_budgetTable) {
551 if (att == QStringLiteral("f_DELTA") || att == QStringLiteral("f_DELTABEFORETRANSFER")) {
552 double val = SKGServices::stringToDouble(obj->getAttribute(att));
553 if (val < -EPSILON) {
554 return m_iconRed;
555 }
556 if (val > EPSILON) {
557 return m_iconGreen;
558 }
559 double transferred = SKGServices::stringToDouble(obj->getAttribute(QStringLiteral("f_transferred")));
560 if (transferred < -EPSILON) {
561 return m_iconAnber;
562 }
563 return m_iconGreen;
564 }
565 }
566 break;
567 }
568 case Qt::TextColorRole: {
569 // Text color
570 QString att = m_listAttibutes[iIndex.column()];
571 if (m_recurrentoperationTable) {
572 if (obj->getAttribute(QStringLiteral("i_nb_times")) == QStringLiteral("0")) {
573 return m_fontDisabledScheduleColor;
574 }
575 if (att == QStringLiteral("d_date") && SKGServices::stringToTime(obj->getAttribute(QStringLiteral("d_date"))).date() <= QDate::currentDate()) {
576 return m_fontNegativeColor;
577 }
578 } else if (m_operationTable) {
579 if (SKGServices::stringToTime(obj->getAttribute(QStringLiteral("d_date"))).date() > QDate::currentDate()) {
580 return m_fontFutureOperationsColor;
581 }
582 if (getAttributeType(iIndex.column()) != SKGServices::FLOAT) {
583 if (obj->getAttribute(QStringLiteral("t_imported")) == QStringLiteral("P")) {
584 return m_fontNotValidatedOperationsColor;
585 }
586 if (m_suboperationTable) {
587 return m_fontSubOperationsColor;
588 }
589 }
590 }
591 break;
592 }
593 case Qt::TextAlignmentRole: {
594 // Text alignment
595 if (m_recurrentoperationTable) {
596 QString att = m_listAttibutes[iIndex.column()];
597
598 if (att == QStringLiteral("i_auto_write_days") || att == QStringLiteral("i_warn_days") || att == QStringLiteral("i_nb_times")) {
599 return static_cast<int>(Qt::AlignVCenter | Qt::AlignLeft);
600 }
601 }
602 break;
603 }
604 case Qt::CheckStateRole: {
605 // CheckState
606 QString att = m_listAttibutes[iIndex.column()];
607 if (m_operationTable && att == QStringLiteral("t_status")) {
608 QString cond = obj->getAttribute(QStringLiteral("t_status"));
609 if (cond == QStringLiteral("P")) {
610 return static_cast<int>(Qt::PartiallyChecked);
611 }
612 if (cond == QStringLiteral("Y")) {
613 return static_cast<int>(Qt::Checked);
614 }
615 if (cond == QStringLiteral("N")) {
616 return static_cast<int>(Qt::Unchecked);
617 }
618 } else if (att == QStringLiteral("t_close")) {
619 QString cond = obj->getAttribute(QStringLiteral("t_close"));
620 if (cond == QStringLiteral("Y")) {
621 return static_cast<int>(Qt::Checked);
622 }
623 return static_cast<int>(Qt::Unchecked);
624
625 } else if (m_recurrentoperationTable && att == QStringLiteral("i_auto_write_days")) {
626 QString cond = obj->getAttribute(QStringLiteral("t_auto_write"));
627 if (cond == QStringLiteral("Y")) {
628 return static_cast<int>(Qt::Checked);
629 }
630 return static_cast<int>(Qt::Unchecked);
631
632 } else if (m_recurrentoperationTable && att == QStringLiteral("i_warn_days")) {
633 QString cond = obj->getAttribute(QStringLiteral("t_warn"));
634 if (cond == QStringLiteral("Y")) {
635 return static_cast<int>(Qt::Checked);
636 }
637 return static_cast<int>(Qt::Unchecked);
638
639 } else if (m_recurrentoperationTable && att == QStringLiteral("i_nb_times")) {
640 QString cond = obj->getAttribute(QStringLiteral("t_times"));
641 if (cond == QStringLiteral("Y")) {
642 return static_cast<int>(Qt::Checked);
643 }
644 return static_cast<int>(Qt::Unchecked);
645
646 } else if (m_budgetRuleTable && att == QStringLiteral("t_CATEGORYCONDITION")) {
647 QString cond = obj->getAttribute(QStringLiteral("t_category_condition"));
648 if (cond == QStringLiteral("Y")) {
649 return static_cast<int>(Qt::Checked);
650 }
651 return static_cast<int>(Qt::Unchecked);
652
653 } else if (m_budgetRuleTable && att == QStringLiteral("i_year")) {
654 QString cond = obj->getAttribute(QStringLiteral("t_year_condition"));
655 if (cond == QStringLiteral("Y")) {
656 return static_cast<int>(Qt::Checked);
657 }
658 return static_cast<int>(Qt::Unchecked);
659
660 } else if (m_budgetRuleTable && att == QStringLiteral("i_month")) {
661 QString cond = obj->getAttribute(QStringLiteral("t_month_condition"));
662 if (cond == QStringLiteral("Y")) {
663 return static_cast<int>(Qt::Checked);
664 }
665 return static_cast<int>(Qt::Unchecked);
666
667 } else if (m_budgetRuleTable && att == QStringLiteral("t_CATEGORY")) {
668 QString cond = obj->getAttribute(QStringLiteral("t_category_target"));
669 if (cond == QStringLiteral("Y")) {
670 return static_cast<int>(Qt::Checked);
671 }
672 return static_cast<int>(Qt::Unchecked);
673
674 } else if (m_budgetTable && att == QStringLiteral("t_CATEGORY")) {
675 QString cond = obj->getAttribute(QStringLiteral("t_including_subcategories"));
676 if (cond == QStringLiteral("Y")) {
677 return static_cast<int>(Qt::Checked);
678 }
679 return static_cast<int>(Qt::Unchecked);
680 }
681 break;
682 }
683 case Qt::ToolTipRole: {
684 // Tooltip
685 QString toolTipString;
686 QString att = m_listAttibutes[iIndex.column()];
687 if (getAttributeType(iIndex.column()) == SKGServices::FLOAT) {
688 // Add secondary unit
689 if (!att.contains(QStringLiteral("QUANTITY")) && att != QStringLiteral("f_coef") && att != QStringLiteral("f_rate")) {
690 SKGServices::SKGUnitInfo secondaryUnit = qobject_cast<SKGDocumentBank*>(getDocument())->getSecondaryUnit();
691 if (!secondaryUnit.Symbol.isEmpty()) {
692 double val = SKGServices::stringToDouble(obj->getAttribute(att));
693 if ((!att.endsWith(QLatin1String("_INCOME")) && !att.endsWith(QLatin1String("_EXPENSE"))) || val != 0) {
694 if (secondaryUnit.Value != 0.0) {
695 toolTipString = SKGServices::toCurrencyString(val / secondaryUnit.Value, secondaryUnit.Symbol, secondaryUnit.NbDecimal);
696 }
697 }
698 }
699 }
700
701 // Add balance
702 if (m_operationTable && !m_suboperationTable) {
703 SKGOperationObject op(*obj);
704 if (!op.isTemplate()) {
705 SKGServices::SKGUnitInfo primaryUnit = qobject_cast<SKGDocumentBank*>(getDocument())->getPrimaryUnit();
706
707 // Add original amount
708 QString originalAmount = obj->getProperty(QStringLiteral("SKG_OP_ORIGINAL_AMOUNT"));
709 if (!originalAmount.isEmpty()) {
710 if (!toolTipString.isEmpty()) {
711 toolTipString += QStringLiteral("\n\n");
712 }
713 double val1 = SKGServices::stringToDouble(obj->getAttribute(QStringLiteral("f_CURRENTAMOUNT")));
714 double val2 = SKGServices::stringToDouble(originalAmount);
715 double gain = (val2 != 0 ? 100.0 * (val1 - val2) / val2 : 0);
716 double gainperyear = gain;
717
718 int nbDays = op.getDate().daysTo(QDate::currentDate());
719 if (nbDays != 0 && val2 != 0) {
720 double gainperday = 100.0 * expm1(log(val1 / val2) / static_cast<double>(nbDays));
721 gainperyear = 100.0 * (pow(1.0 + gainperday / 100.0, 365.0) - 1);
722 }
723 toolTipString += i18nc("Noun", "Original amount=%1 (%2 = %3 / year)",
724 SKGServices::toCurrencyString(val2, primaryUnit.Symbol, primaryUnit.NbDecimal),
725 (gain >= 0 ? "+" : "-") % SKGServices::toPercentageString(gain, 2),
726 (gainperyear >= 0 ? "+" : "-") % SKGServices::toPercentageString(gainperyear, 2));
727 } else {
728 if (!toolTipString.isEmpty()) {
729 toolTipString += QStringLiteral("\n\n");
730 }
731 double val1 = SKGServices::stringToDouble(obj->getAttribute(QStringLiteral("f_CURRENTAMOUNT")));
732 double val2 = op.getAmount(op.getDate());
733 double gain = (val2 != 0 ? 100.0 * (val1 - val2) / val2 : 0);
734 double gainperyear = gain;
735
736 int nbDays = op.getDate().daysTo(QDate::currentDate());
737 if (nbDays != 0 && val2 != 0) {
738 double gainperday = 100.0 * expm1(log(val1 / val2) / static_cast<double>(nbDays));
739 gainperyear = 100.0 * (pow(1.0 + gainperday / 100.0, 365.0) - 1);
740 }
741
742 QString sval1 = SKGServices::toCurrencyString(val1, primaryUnit.Symbol, primaryUnit.NbDecimal);
743 QString sval2 = SKGServices::toCurrencyString(val2, primaryUnit.Symbol, primaryUnit.NbDecimal);
744 if (sval1 != sval2) {
745 toolTipString += i18nc("Noun", "Amount at creation date=%1 (%2 = %3 / year)",
746 sval2,
747 (gain >= 0 ? "+" : "-") % SKGServices::toPercentageString(gain, 2),
748 (gainperyear >= 0 ? "+" : "-") % SKGServices::toPercentageString(gainperyear, 2));
749
750 toolTipString += '\n';
751 }
752 }
753 toolTipString += i18nc("Noun", "Account balance=%1",
754 SKGServices::toCurrencyString(op.getBalance(), primaryUnit.Symbol, primaryUnit.NbDecimal));
755 }
756 }
757
758 if (m_budgetTable) {
759 if (att == QStringLiteral("f_DELTA")) {
760 double val = SKGServices::stringToDouble(obj->getAttribute(QStringLiteral("f_DELTABEFORETRANSFER")));
761
762 if (!toolTipString.isEmpty()) {
763 toolTipString += QStringLiteral("\n\n");
764 }
765
766 SKGServices::SKGUnitInfo primaryUnit = qobject_cast<SKGDocumentBank*>(getDocument())->getPrimaryUnit();
767 toolTipString += i18nc("Noun", "Original delta=%1",
768 SKGServices::toCurrencyString(val, primaryUnit.Symbol, primaryUnit.NbDecimal));
769 } else if (att == QStringLiteral("f_budgeted_modified")) {
770 QString reasons = obj->getAttribute(QStringLiteral("t_modification_reasons"));
771 if (!reasons.isEmpty()) {
772 if (!toolTipString.isEmpty()) {
773 toolTipString += QStringLiteral("\n\n");
774 }
775 toolTipString += reasons;
776 }
777 }
778 }
779
780 if (m_unitTable) {
781 if (att == QStringLiteral("f_CURRENTAMOUNT")) {
782 SKGUnitObject unit(*obj);
783 double amountOneYearBefore = unit.getAmount(QDate::currentDate().addYears(-1));
784 double annualchange = 100.0 * (unit.getAmount() - amountOneYearBefore) / amountOneYearBefore;
785 if (!toolTipString.isEmpty()) {
786 toolTipString += QStringLiteral("\n\n");
787 }
788 toolTipString += SKGServices::toPercentageString(annualchange);
789 }
790 }
791 } else if (m_operationTable || m_recurrentoperationTable) {
792 if (att == QStringLiteral("t_imported")) {
793 if (!m_suboperationTable) {
794 SKGOperationObject op;
795 if (m_recurrentoperationTable) {
796 SKGRecurrentOperationObject rop(*obj);
797 rop.getParentOperation(op);
798 } else {
799 op = *obj;
800 }
801 toolTipString = op.getImportID();
802 }
803 } else if (att == QStringLiteral("t_REFUND") || att == QStringLiteral("t_REALREFUND") || att == QStringLiteral("t_REFUNDDISPLAY")) {
804 if (att == QStringLiteral("t_REFUNDDISPLAY")) {
805 if (obj->getAttribute(att).count(QStringLiteral("(")) > 1) {
806 att.clear();
807 } else {
808 att = QStringLiteral("t_REFUND");
809 }
810 }
811 if (!att.isEmpty()) {
812 QString trackerName = obj->getAttribute(att);
813 if (!trackerName.isEmpty()) {
814 SKGTrackerObject tracker(getDocument());
815 tracker.setName(trackerName);
816 tracker.load();
817 SKGServices::SKGUnitInfo unit = qobject_cast<SKGDocumentBank*>(getDocument())->getPrimaryUnit();
818 toolTipString = SKGServices::toCurrencyString(tracker.getCurrentAmount(), unit.Symbol, unit.NbDecimal);
819 }
820 }
821 } else if (att == QStringLiteral("t_PAYEE")) {
822 QString payeeName = obj->getAttribute(att);
823 if (!payeeName.isEmpty()) {
824 SKGPayeeObject payee(getDocument());
825 payee.setName(payeeName);
826 payee.load();
827
828 auto address = payee.getAddress();
829 if (!address.isEmpty()) {
830 toolTipString += i18nc("Information", "Address= %1\n", address);
831 }
832
833 auto c = payee.getAttribute(QStringLiteral("t_CATEGORY"));
834 if (c.isEmpty()) {
835 c = qobject_cast<SKGDocumentBank*>(getDocument())->getCategoryForPayee(payeeName, false);
836 }
837 if (!c.isEmpty()) {
838 toolTipString += i18nc("Information", "Category= %1\n", c);
839 }
840 }
841 } else if (att == QStringLiteral("t_ACCOUNT") || att == QStringLiteral("t_TOACCOUNT")) {
842 QString accountName = obj->getAttribute(att);
843 if (!accountName.isEmpty()) {
844 SKGAccountObject account(getDocument());
845 account.setName(accountName);
846 account.load();
847
848 auto tmp = account.getAgencyNumber();
849 if (!tmp.isEmpty()) {
850 toolTipString += i18nc("Information", "Agency number= %1\n", tmp);
851 }
852
853 tmp = account.getNumber();
854 if (!tmp.isEmpty()) {
855 toolTipString += i18nc("Information", "Number= %1\n", tmp);
856 }
857
858 tmp = account.getAgencyAddress();
859 if (!tmp.isEmpty()) {
860 toolTipString += i18nc("Information", "Address= %1\n", tmp);
861 }
862
863 tmp = account.getComment();
864 if (!tmp.isEmpty()) {
865 toolTipString += i18nc("Information", "Comment= %1\n", tmp);
866 }
867 }
868 } else if (att == QStringLiteral("t_CATEGORY")) {
869 SKGOperationObject op(*obj);
870 if (m_recurrentoperationTable) {
871 SKGRecurrentOperationObject rop(*obj);
872 rop.getParentOperation(op);
873 }
874 if (SKGServices::stringToInt(op.getAttribute(QStringLiteral("i_NBSUBOPERATIONS"))) > 1) {
875 SKGObjectBase::SKGListSKGObjectBase subOps;
876 op.getSubOperations(subOps);
877 for (const auto& subOp : qAsConst(subOps)) {
878 toolTipString += subOp.getDisplayName() % '\n';
879 }
880 }
881 } else if (att == QStringLiteral("t_mode")) {
882 SKGOperationObject op(*obj);
883 if (m_recurrentoperationTable) {
884 SKGRecurrentOperationObject rop(*obj);
885 rop.getParentOperation(op);
886 }
887 if (op.getAttribute(QStringLiteral("i_group_id")) != QStringLiteral("0")) {
888 SKGOperationObject gop;
889 op.getGroupOperation(gop);
890
891 SKGObjectBase::SKGListSKGObjectBase gOps;
892 op.getGroupedOperations(gOps);
893 for (const auto& item : qAsConst(gOps)) {
894 SKGOperationObject gOp(item);
895 SKGAccountObject account;
896 gOp.getParentAccount(account);
897 toolTipString += account.getDisplayName() % '\n';
898 }
899 }
900 }
901
902 if (m_operationTable && !m_suboperationTable && toolTipString.isEmpty()) {
903 SKGOperationObject op(*obj);
904 if (op.getStatus() == SKGOperationObject::POINTED) {
905 toolTipString = i18nc("A tool tip", "This operation is pointed but not checked yet.");
906 toolTipString += '\n';
907 toolTipString += i18nc("A tool tip", "You can use the reconciliation mode to validate pointed operations.");
908 toolTipString += '\n';
909 if (att == QStringLiteral("t_status")) {
910 toolTipString += i18nc("A tool tip", "Click in this column to switch back status.");
911 } else {
912 toolTipString += i18nc("A tool tip", "Click in the Status (checkmark) column to switch back status.");
913 }
914 toolTipString += '\n';
915 toolTipString += i18nc("A tool tip", "Ctrl+click to force checked status.");
916 } else if (op.getStatus() == SKGOperationObject::CHECKED) {
917 toolTipString = i18nc("A tool tip", "This operation is already checked.");
918 } else if (op.getStatus() == SKGOperationObject::NONE) {
919 toolTipString = i18nc("A tool tip", "This operation is not pointed yet.");
920 toolTipString += '\n';
921 toolTipString += i18nc("A tool tip", "Click to set pointed status.");
922 toolTipString += '\n';
923 toolTipString += i18nc("A tool tip", "Ctrl+click to force checked status.");
924 }
925 }
926 } else if (m_ruleTable && att == QStringLiteral("t_action_type")) {
927 QString val = obj->getAttribute(att);
928 if (val == QStringLiteral("S")) {
929 toolTipString = i18nc("Noun, a search", "Search");
930 } else if (val == QStringLiteral("U")) {
931 toolTipString = i18nc("Noun, a modification", "Update");
932 } else {
933 toolTipString = i18nc("Noun, an alarm", "Alarm");
934 }
935 }
936
937 QString toolTipStringBase = SKGObjectModelBase::computeData(iIndex, iRole).toString();
938 if (!toolTipStringBase.isEmpty()) {
939 if (!toolTipString.isEmpty()) {
940 toolTipString += QStringLiteral("\n\n");
941 }
942 toolTipString += toolTipStringBase;
943 }
944 return toolTipString;
945 }
946 default: {
947 }
948 }
949 return SKGObjectModelBase::computeData(iIndex, iRole);
950 }
951
setData(const QModelIndex & iIndex,const QVariant & iValue,int iRole)952 bool SKGObjectModel::setData(const QModelIndex& iIndex, const QVariant& iValue, int iRole)
953 {
954 if (!iIndex.isValid()) {
955 return false;
956 }
957
958 if (iRole == Qt::CheckStateRole) {
959 SKGError err;
960 {
961 auto newState = static_cast<Qt::CheckState>(iValue.toInt());
962 if (m_accountTable) {
963 SKGAccountObject obj(getObject(iIndex));
964 SKGBEGINLIGHTTRANSACTION(*getDocument(),
965 (newState == Qt::Checked ? i18nc("Noun, name of the user action", "Close account '%1'", obj.getName()) : i18nc("Noun, name of the user action", "Open account '%1'", obj.getName())), err);
966 if (qAbs(obj.getCurrentAmount()) > 0.01 && newState == Qt::Checked) {
967 err = getDocument()->sendMessage(i18nc("An information message", "Warning, you closed an account with money"), SKGDocument::Warning);
968 }
969 IFOKDO(err, obj.setClosed(newState == Qt::Checked))
970 IFOKDO(err, obj.save())
971 } else if (m_trackerTable) {
972 SKGTrackerObject obj(getObject(iIndex));
973 SKGBEGINLIGHTTRANSACTION(*getDocument(),
974 (newState == Qt::Checked ? i18nc("Noun, name of the user action", "Close tracker '%1'", obj.getName()) : i18nc("Noun, name of the user action", "Open tracker '%1'", obj.getName())), err);
975 err = obj.setClosed(newState == Qt::Checked);
976 IFOKDO(err, obj.save())
977 } else if (m_categoryTable) {
978 SKGCategoryObject obj(getObject(iIndex));
979 SKGBEGINLIGHTTRANSACTION(*getDocument(),
980 (newState == Qt::Checked ? i18nc("Noun, name of the user action", "Close category '%1'", obj.getName()) : i18nc("Noun, name of the user action", "Open category '%1'", obj.getName())), err);
981 err = obj.setClosed(newState == Qt::Checked);
982 IFOKDO(err, obj.save())
983 } else if (m_payeeTable) {
984 SKGPayeeObject obj(getObject(iIndex));
985 SKGBEGINLIGHTTRANSACTION(*getDocument(),
986 (newState == Qt::Checked ? i18nc("Noun, name of the user action", "Close payee '%1'", obj.getName()) : i18nc("Noun, name of the user action", "Open payee '%1'", obj.getName())), err);
987 err = obj.setClosed(newState == Qt::Checked);
988 IFOKDO(err, obj.save())
989 } else if (m_operationTable && !m_suboperationTable) {
990 // Get the real object, not the object from the view
991 SKGObjectBase* objtmp = getObjectPointer(iIndex);
992 if (objtmp != nullptr) {
993 SKGOperationObject obj = SKGOperationObject(objtmp->getDocument(), objtmp->getID());
994 SKGBEGINLIGHTTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Change operation status"), err)
995 SKGOperationObject::OperationStatus statusinitial = obj.getStatus();
996 SKGOperationObject::OperationStatus t_status = statusinitial;
997 if ((QApplication::keyboardModifiers() & Qt::ControlModifier) != 0u) {
998 // 2747379: NONE ==> CHECKED, POINTED ==> CHECKED, CHECKED ==> CHECKED
999 t_status = SKGOperationObject::CHECKED;
1000 // t_status= ( t_status==SKGOperationObject::POINTED ? SKGOperationObject::NONE : ( t_status==SKGOperationObject::CHECKED ? SKGOperationObject::POINTED : SKGOperationObject::NONE ) );
1001 } else {
1002 // 2747379: NONE ==> POINTED, POINTED ==> NONE, CHECKED ==> POINTED
1003 t_status = (t_status == SKGOperationObject::NONE ? SKGOperationObject::POINTED : (t_status == SKGOperationObject::POINTED ? SKGOperationObject::NONE : SKGOperationObject::POINTED));
1004 // t_status=(t_status==SKGOperationObject::POINTED ? SKGOperationObject::CHECKED : (t_status==SKGOperationObject::CHECKED ? SKGOperationObject::CHECKED : SKGOperationObject::POINTED ));
1005 }
1006 if (t_status != statusinitial) {
1007 err = obj.setStatus(t_status);
1008 IFOKDO(err, obj.save())
1009
1010 // Send message
1011 IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The status of the operation '%1' has been changed", obj.getDisplayName()), SKGDocument::Hidden))
1012 }
1013 }
1014 } else if (m_recurrentoperationTable) {
1015 QString att = m_listAttibutes[iIndex.column()];
1016
1017 // Get the real object, not the object from the view
1018 SKGObjectBase* objtmp = getObjectPointer(iIndex);
1019 if (objtmp != nullptr) {
1020 SKGRecurrentOperationObject obj = SKGRecurrentOperationObject(objtmp->getDocument(), objtmp->getID());
1021
1022 SKGBEGINLIGHTTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Recurrent operation update"), err)
1023 if (att == QStringLiteral("i_warn_days")) {
1024 err = obj.warnEnabled(!obj.isWarnEnabled());
1025 } else if (att == QStringLiteral("i_auto_write_days")) {
1026 err = obj.autoWriteEnabled(!obj.isAutoWriteEnabled());
1027 } else if (att == QStringLiteral("i_nb_times")) {
1028 err = obj.timeLimit(!obj.hasTimeLimit());
1029 }
1030 IFOKDO(err, obj.save())
1031
1032 // Send message
1033 IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The recurrent operation '%1' has been updated", obj.getDisplayName()), SKGDocument::Hidden))
1034 }
1035 } else if (m_budgetRuleTable) {
1036 QString att = m_listAttibutes[iIndex.column()];
1037
1038 // Get the real object, not the object from the view
1039 SKGObjectBase* objtmp = getObjectPointer(iIndex);
1040 if (objtmp != nullptr) {
1041 SKGBudgetRuleObject obj = SKGBudgetRuleObject(objtmp->getDocument(), objtmp->getID());
1042
1043 SKGBEGINLIGHTTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Budget rule update"), err)
1044 if (att == QStringLiteral("i_year")) {
1045 err = obj.enableYearCondition(!obj.isYearConditionEnabled());
1046 } else if (att == QStringLiteral("i_month")) {
1047 err = obj.enableMonthCondition(!obj.isMonthConditionEnabled());
1048 } else if (att == QStringLiteral("t_CATEGORYCONDITION")) {
1049 err = obj.enableCategoryCondition(!obj.isCategoryConditionEnabled());
1050 } else if (att == QStringLiteral("t_CATEGORY")) {
1051 err = obj.enableCategoryChange(!obj.isCategoryChangeEnabled());
1052 }
1053 IFOKDO(err, obj.save())
1054
1055 // Send message
1056 IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The budget rule '%1' has been updated", obj.getDisplayName()), SKGDocument::Hidden))
1057 }
1058 } else if (m_budgetTable) {
1059 QString att = m_listAttibutes[iIndex.column()];
1060
1061 // Get the real object, not the object from the view
1062 SKGObjectBase* objtmp = getObjectPointer(iIndex);
1063 if (objtmp != nullptr) {
1064 SKGBudgetObject obj = SKGBudgetObject(objtmp->getDocument(), objtmp->getID());
1065
1066 SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Budget update"), err)
1067 if (att == QStringLiteral("t_CATEGORY")) {
1068 IFOKDO(err, obj.enableSubCategoriesInclusion(!obj.isSubCategoriesInclusionEnabled()))
1069 IFOKDO(err, obj.save())
1070
1071 // Send message
1072 IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The budget '%1' have been updated", obj.getDisplayName()), SKGDocument::Hidden))
1073 }
1074 }
1075 }
1076 }
1077
1078 SKGMainPanel::displayErrorMessage(err);
1079 return !err;
1080 }
1081 return SKGObjectModelBase::setData(iIndex, iValue, iRole);
1082 }
1083
flags(const QModelIndex & iIndex) const1084 Qt::ItemFlags SKGObjectModel::flags(const QModelIndex& iIndex) const
1085 {
1086 _SKGTRACEINFUNC(10)
1087
1088 Qt::ItemFlags f = SKGObjectModelBase::flags(iIndex);
1089
1090 if (iIndex.isValid()) {
1091 QString att = m_listAttibutes[iIndex.column()];
1092 if (att == QStringLiteral("t_bookmarked") || m_ruleTable || m_recurrentoperationTable || m_interestTable || m_interestResultTable) {
1093 f = f & ~Qt::ItemIsEditable;
1094 }
1095 }
1096
1097 if (m_categoryTable || m_payeeTable || m_accountTable || m_unitTable || m_trackerTable) {
1098 if (iIndex.isValid()) {
1099 f |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
1100 } else {
1101 f |= Qt::ItemIsDropEnabled;
1102 }
1103 }
1104
1105 return f;
1106 }
1107
supportedDragActions() const1108 Qt::DropActions SKGObjectModel::supportedDragActions() const
1109 {
1110 if (m_categoryTable || m_payeeTable || m_accountTable || m_unitTable || m_trackerTable) {
1111 return Qt::MoveAction;
1112 }
1113 return SKGObjectModelBase::supportedDragActions();
1114 }
1115
supportedDropActions() const1116 Qt::DropActions SKGObjectModel::supportedDropActions() const
1117 {
1118 return SKGObjectModelBase::supportedDropActions();
1119 }
1120
dropMimeData(const QMimeData * iData,Qt::DropAction iAction,int iRow,int iColumn,const QModelIndex & iParent)1121 bool SKGObjectModel::dropMimeData(const QMimeData* iData,
1122 Qt::DropAction iAction,
1123 int iRow, int iColumn,
1124 const QModelIndex& iParent)
1125 {
1126 if (SKGObjectModelBase::dropMimeData(iData, iAction, iRow, iColumn, iParent)) {
1127 return true;
1128 }
1129 if (iAction == Qt::IgnoreAction) {
1130 return true;
1131 }
1132 if ((iData == nullptr) || !(iData->hasFormat(QStringLiteral("application/skg.category.ids")) ||
1133 iData->hasFormat(QStringLiteral("application/skg.payee.ids")) ||
1134 iData->hasFormat(QStringLiteral("application/skg.account.ids")) ||
1135 iData->hasFormat(QStringLiteral("application/skg.refund.ids")) ||
1136 iData->hasFormat(QStringLiteral("application/skg.unit.ids")))) {
1137 return false;
1138 }
1139 if (iColumn > 0) {
1140 return false;
1141 }
1142
1143 SKGError err;
1144 if (iData->hasFormat(QStringLiteral("application/skg.category.ids"))) {
1145 QByteArray encodedData = iData->data(QStringLiteral("application/skg.category.ids"));
1146 QDataStream stream(&encodedData, QIODevice::ReadOnly);
1147 QStringList newItems;
1148
1149 SKGCategoryObject parentCategory;
1150 if (iParent.isValid()) {
1151 parentCategory = getObject(iParent);
1152 }
1153 {
1154 SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Move category"), err)
1155
1156 while (!stream.atEnd() && !err) {
1157 int o_id;
1158 QString o_table;
1159 stream >> o_table;
1160 stream >> o_id;
1161
1162 SKGCategoryObject child(getDocument(), o_id);
1163 err = child.load();
1164 QString oldName = child.getDisplayName();
1165 IFOK(err) {
1166 if (iParent.isValid()) {
1167 err = child.setParentCategory(parentCategory);
1168 } else {
1169 err = child.removeParentCategory();
1170 }
1171 }
1172 IFOKDO(err, child.save())
1173
1174 // Send message
1175 IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The category '%1' has been moved to '%2'", oldName, child.getDisplayName()), SKGDocument::Hidden))
1176 }
1177 }
1178 } else if (iData->hasFormat(QStringLiteral("application/skg.payee.ids"))) {
1179 QByteArray encodedData = iData->data(QStringLiteral("application/skg.payee.ids"));
1180 QDataStream stream(&encodedData, QIODevice::ReadOnly);
1181 QStringList newItems;
1182
1183 if (iParent.isValid()) {
1184 SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Merge payees"), err)
1185 SKGPayeeObject parentPayee(getObject(iParent));
1186 while (!stream.atEnd() && !err) {
1187 int o_id;
1188 QString o_table;
1189 stream >> o_table;
1190 stream >> o_id;
1191
1192 SKGPayeeObject child(getDocument(), o_id);
1193 err = child.load();
1194
1195 // Send message
1196 IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The payee '%1' has been merged with payee '%2'", child.getDisplayName(), parentPayee.getDisplayName()), SKGDocument::Hidden))
1197
1198 IFOKDO(err, parentPayee.merge(child))
1199 }
1200 }
1201 } else if (iData->hasFormat(QStringLiteral("application/skg.account.ids"))) {
1202 QByteArray encodedData = iData->data(QStringLiteral("application/skg.account.ids"));
1203 QDataStream stream(&encodedData, QIODevice::ReadOnly);
1204 QStringList newItems;
1205
1206 if (iParent.isValid()) {
1207 SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Merge accounts"), err)
1208 SKGAccountObject parentAccount(getObject(iParent));
1209 while (!stream.atEnd() && !err) {
1210 int o_id;
1211 QString o_table;
1212 stream >> o_table;
1213 stream >> o_id;
1214
1215 SKGAccountObject child(getDocument(), o_id);
1216 err = child.load();
1217
1218 // Send message
1219 IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The account '%1' has been merged with account '%2'", child.getDisplayName(), parentAccount.getDisplayName()), SKGDocument::Hidden))
1220
1221 double balancebefore = 0.0;
1222 double balanceafter = 0.0;
1223 SKGUnitObject unit2;
1224 IFOKDO(err, parentAccount.getInitialBalance(balancebefore, unit2))
1225 IFOKDO(err, parentAccount.merge(child, !(QApplication::keyboardModifiers() &Qt::ControlModifier)))
1226 IFOKDO(err, parentAccount.getInitialBalance(balanceafter, unit2))
1227 if (balanceafter != balancebefore) {
1228 getDocument()->sendMessage(i18nc("Warning message", "The initial balance of the target account '%1' has been change to %2.\nIf you want to do the merge without changing the initial balance, you must keep the Ctrl key pressed.", parentAccount.getDisplayName(), balanceafter), SKGDocument::Warning);
1229 }
1230 }
1231 }
1232 } else if (iData->hasFormat(QStringLiteral("application/skg.unit.ids"))) {
1233 QByteArray encodedData = iData->data(QStringLiteral("application/skg.unit.ids"));
1234 QDataStream stream(&encodedData, QIODevice::ReadOnly);
1235 QStringList newItems;
1236
1237 if (iParent.isValid()) {
1238 SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Merge units"), err)
1239 SKGUnitObject parentUnit(getObject(iParent));
1240 while (!stream.atEnd() && !err) {
1241 int o_id;
1242 QString o_table;
1243 stream >> o_table;
1244 stream >> o_id;
1245
1246 SKGUnitObject child(getDocument(), o_id);
1247 err = child.load();
1248
1249 // Send message
1250 IFOKDO(err, getDocument()->sendMessage(i18nc("An information to the user", "The unit '%1' has been merged with unit '%2'", child.getDisplayName(), parentUnit.getDisplayName()), SKGDocument::Hidden))
1251
1252 IFOKDO(err, parentUnit.merge(child))
1253 }
1254 }
1255 } else if (iData->hasFormat(QStringLiteral("application/skg.refund.ids"))) {
1256 QByteArray encodedData = iData->data(QStringLiteral("application/skg.refund.ids"));
1257 QDataStream stream(&encodedData, QIODevice::ReadOnly);
1258 QStringList newItems;
1259
1260 if (iParent.isValid()) {
1261 SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Merge trackers"), err)
1262 SKGTrackerObject parentTracker(getObject(iParent));
1263 while (!stream.atEnd() && !err) {
1264 int o_id;
1265 QString o_table;
1266 stream >> o_table;
1267 stream >> o_id;
1268
1269 SKGTrackerObject child(getDocument(), o_id);
1270 err = child.load();
1271
1272 // Send message
1273 IFOKDO(err, parentTracker.getDocument()->sendMessage(i18nc("An information to the user", "The tracker '%1' has been merged with tracker '%2'", child.getDisplayName(), parentTracker.getDisplayName()), SKGDocument::Hidden))
1274
1275 IFOKDO(err, parentTracker.merge(child))
1276 }
1277 }
1278 }
1279 SKGMainPanel::displayErrorMessage(err);
1280 return !err;
1281 }
1282
dataModified(const QString & iTableName,int iIdTransaction)1283 void SKGObjectModel::dataModified(const QString& iTableName, int iIdTransaction)
1284 {
1285 if (getRealTable() == iTableName || iTableName.isEmpty() || getRealTable() == QStringLiteral("doctransaction")) {
1286 SKGTRACEINFUNC(1)
1287 if (iTableName == QStringLiteral("category")) {
1288 // Full refresh
1289 m_isResetRealyNeeded = true;
1290 refresh();
1291 } else {
1292 SKGObjectModelBase::dataModified(iTableName, iIdTransaction);
1293 }
1294 } else {
1295 SKGObjectModelBase::dataModified(iTableName, iIdTransaction);
1296 }
1297 }
1298
formatMoney(double iValue) const1299 QString SKGObjectModel::formatMoney(double iValue) const
1300 {
1301 return getDocument()->formatMoney(iValue, qobject_cast<SKGDocumentBank*>(getDocument())->getPrimaryUnit(), false);
1302 }
1303
1304
1305
1306