Changeset View
Standalone View
kmymoney/kmymoney.cpp
Show First 20 Lines • Show All 61 Lines • ▼ Show 20 Line(s) | |||||
62 | #include <KTipDialog> | 62 | #include <KTipDialog> | ||
63 | #include <KRun> | 63 | #include <KRun> | ||
64 | #include <KConfigDialog> | 64 | #include <KConfigDialog> | ||
65 | #include <KXMLGUIFactory> | 65 | #include <KXMLGUIFactory> | ||
66 | #include <KRecentFilesAction> | 66 | #include <KRecentFilesAction> | ||
67 | #include <KRecentDirs> | 67 | #include <KRecentDirs> | ||
68 | #include <KProcess> | 68 | #include <KProcess> | ||
69 | #include <KAboutApplicationDialog> | 69 | #include <KAboutApplicationDialog> | ||
70 | #include <KIO/StoredTransferJob> | ||||
71 | #include <KJobWidgets> | ||||
72 | #include <KCompressionDevice> | ||||
73 | #include <KBackup> | ||||
70 | #ifdef KF5Holidays_FOUND | 74 | #ifdef KF5Holidays_FOUND | ||
71 | #include <KHolidays/Holiday> | 75 | #include <KHolidays/Holiday> | ||
72 | #include <KHolidays/HolidayRegion> | 76 | #include <KHolidays/HolidayRegion> | ||
73 | #endif | 77 | #endif | ||
74 | 78 | | |||
75 | // ---------------------------------------------------------------------------- | 79 | // ---------------------------------------------------------------------------- | ||
76 | // Project Includes | 80 | // Project Includes | ||
77 | 81 | | |||
Show All 25 Lines | |||||
103 | #include "dialogs/ktemplateexportdlg.h" | 107 | #include "dialogs/ktemplateexportdlg.h" | ||
104 | #include "dialogs/transactionmatcher.h" | 108 | #include "dialogs/transactionmatcher.h" | ||
105 | #include "wizards/newuserwizard/knewuserwizard.h" | 109 | #include "wizards/newuserwizard/knewuserwizard.h" | ||
106 | #include "wizards/newaccountwizard/knewaccountwizard.h" | 110 | #include "wizards/newaccountwizard/knewaccountwizard.h" | ||
107 | #include "dialogs/kbalancewarning.h" | 111 | #include "dialogs/kbalancewarning.h" | ||
108 | #include "widgets/kmymoneyaccountselector.h" | 112 | #include "widgets/kmymoneyaccountselector.h" | ||
109 | #include "widgets/kmymoneypayeecombo.h" | 113 | #include "widgets/kmymoneypayeecombo.h" | ||
110 | #include "widgets/onlinejobmessagesview.h" | 114 | #include "widgets/onlinejobmessagesview.h" | ||
111 | 115 | #include "widgets/amountedit.h" | |||
116 | #include "widgets/kmymoneyedit.h" | ||||
112 | #include "widgets/kmymoneymvccombo.h" | 117 | #include "widgets/kmymoneymvccombo.h" | ||
113 | 118 | | |||
114 | #include "views/kmymoneyview.h" | 119 | #include "views/kmymoneyview.h" | ||
115 | #include "views/konlinejoboutbox.h" | 120 | #include "views/konlinejoboutbox.h" | ||
116 | #include "models/onlinejobmessagesmodel.h" | 121 | #include "models/onlinejobmessagesmodel.h" | ||
122 | #include "models/models.h" | ||||
123 | #include "models/accountsmodel.h" | ||||
124 | #include "models/equitiesmodel.h" | ||||
125 | #include "models/securitiesmodel.h" | ||||
117 | 126 | | |||
118 | #include "mymoney/mymoneyobject.h" | 127 | #include "mymoney/mymoneyobject.h" | ||
119 | #include "mymoney/mymoneyfile.h" | 128 | #include "mymoney/mymoneyfile.h" | ||
120 | #include "mymoney/mymoneyinstitution.h" | 129 | #include "mymoney/mymoneyinstitution.h" | ||
121 | #include "mymoney/mymoneyaccount.h" | 130 | #include "mymoney/mymoneyaccount.h" | ||
122 | #include "mymoney/mymoneyaccountloan.h" | 131 | #include "mymoney/mymoneyaccountloan.h" | ||
123 | #include "mymoney/mymoneysecurity.h" | 132 | #include "mymoney/mymoneysecurity.h" | ||
124 | #include "mymoney/mymoneypayee.h" | 133 | #include "mymoney/mymoneypayee.h" | ||
134 | #include "mymoney/mymoneyprice.h" | ||||
125 | #include "mymoney/mymoneytag.h" | 135 | #include "mymoney/mymoneytag.h" | ||
126 | #include "mymoney/mymoneybudget.h" | 136 | #include "mymoney/mymoneybudget.h" | ||
127 | #include "mymoney/mymoneyreport.h" | 137 | #include "mymoney/mymoneyreport.h" | ||
128 | #include "mymoney/mymoneysplit.h" | 138 | #include "mymoney/mymoneysplit.h" | ||
129 | #include "mymoney/mymoneyutils.h" | 139 | #include "mymoney/mymoneyutils.h" | ||
130 | #include "mymoney/mymoneystatement.h" | 140 | #include "mymoney/mymoneystatement.h" | ||
131 | #include "mymoney/mymoneyforecast.h" | 141 | #include "mymoney/mymoneyforecast.h" | ||
132 | #include "mymoney/mymoneytransactionfilter.h" | 142 | #include "mymoney/mymoneytransactionfilter.h" | ||
Show All 13 Lines | |||||
146 | 156 | | |||
147 | #include "tasks/credittransfer.h" | 157 | #include "tasks/credittransfer.h" | ||
148 | 158 | | |||
149 | #include "icons/icons.h" | 159 | #include "icons/icons.h" | ||
150 | 160 | | |||
151 | #include "misc/webconnect.h" | 161 | #include "misc/webconnect.h" | ||
152 | 162 | | |||
153 | #include "storage/mymoneystoragemgr.h" | 163 | #include "storage/mymoneystoragemgr.h" | ||
164 | #include "storage/mymoneystoragexml.h" | ||||
165 | #include "storage/mymoneystoragebin.h" | ||||
166 | #include "storage/mymoneystorageanon.h" | ||||
154 | 167 | | |||
155 | #include <libkgpgfile/kgpgfile.h> | 168 | #include <libkgpgfile/kgpgfile.h> | ||
156 | 169 | | |||
157 | #include "transactioneditor.h" | 170 | #include "transactioneditor.h" | ||
158 | #include "konlinetransferform.h" | 171 | #include "konlinetransferform.h" | ||
159 | #include <QHBoxLayout> | 172 | #include <QHBoxLayout> | ||
160 | #include <QFileDialog> | 173 | #include <QFileDialog> | ||
161 | 174 | | |||
Show All 11 Lines | |||||
173 | #ifdef KMM_DEBUG | 186 | #ifdef KMM_DEBUG | ||
174 | #include "mymoney/storage/mymoneystoragedump.h" | 187 | #include "mymoney/storage/mymoneystoragedump.h" | ||
175 | #include "mymoneytracer.h" | 188 | #include "mymoneytracer.h" | ||
176 | #endif | 189 | #endif | ||
177 | 190 | | |||
178 | using namespace Icons; | 191 | using namespace Icons; | ||
179 | using namespace eMenu; | 192 | using namespace eMenu; | ||
180 | 193 | | |||
181 | static constexpr char recoveryKeyId[] = "59B0F826D2B08440"; | 194 | static constexpr KCompressionDevice::CompressionType const& COMPRESSION_TYPE = KCompressionDevice::GZip; | ||
195 | static constexpr char recoveryKeyId[] = "0xD2B08440"; | ||||
196 | static constexpr char recoveryKeyId2[] = "59B0F826D2B08440"; | ||||
182 | 197 | | |||
183 | // define the default period to warn about an expiring recoverkey to 30 days | 198 | // define the default period to warn about an expiring recoverkey to 30 days | ||
184 | // but allows to override this setting during build time | 199 | // but allows to override this setting during build time | ||
185 | #ifndef RECOVER_KEY_EXPIRATION_WARNING | 200 | #ifndef RECOVER_KEY_EXPIRATION_WARNING | ||
186 | #define RECOVER_KEY_EXPIRATION_WARNING 30 | 201 | #define RECOVER_KEY_EXPIRATION_WARNING 30 | ||
187 | #endif | 202 | #endif | ||
188 | 203 | | |||
189 | QHash<eMenu::Action, QAction *> pActions; | 204 | QHash<eMenu::Action, QAction *> pActions; | ||
Show All 14 Lines | 217 | Private(KMyMoneyApp *app) : | |||
204 | m_ft(0), | 219 | m_ft(0), | ||
205 | m_moveToAccountSelector(0), | 220 | m_moveToAccountSelector(0), | ||
206 | m_statementXMLindex(0), | 221 | m_statementXMLindex(0), | ||
207 | m_balanceWarning(0), | 222 | m_balanceWarning(0), | ||
208 | m_collectingStatements(false), | 223 | m_collectingStatements(false), | ||
209 | m_backupResult(0), | 224 | m_backupResult(0), | ||
210 | m_backupMount(0), | 225 | m_backupMount(0), | ||
211 | m_ignoreBackupExitCode(false), | 226 | m_ignoreBackupExitCode(false), | ||
227 | m_fileOpen(false), | ||||
228 | m_fmode(QFileDevice::ReadUser | QFileDevice::WriteUser), | ||||
212 | m_myMoneyView(0), | 229 | m_myMoneyView(0), | ||
213 | m_progressBar(0), | 230 | m_progressBar(0), | ||
214 | m_smtReader(0), | 231 | m_smtReader(0), | ||
215 | m_searchDlg(0), | 232 | m_searchDlg(0), | ||
216 | m_autoSaveTimer(0), | 233 | m_autoSaveTimer(0), | ||
217 | m_progressTimer(0), | 234 | m_progressTimer(0), | ||
218 | m_inAutoSaving(false), | 235 | m_inAutoSaving(false), | ||
219 | m_transactionEditor(0), | 236 | m_transactionEditor(0), | ||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Line(s) | 302 | /** | |||
288 | */ | 305 | */ | ||
289 | bool m_backupMount; | 306 | bool m_backupMount; | ||
290 | 307 | | |||
291 | /** | 308 | /** | ||
292 | * Flag for internal run control | 309 | * Flag for internal run control | ||
293 | */ | 310 | */ | ||
294 | bool m_ignoreBackupExitCode; | 311 | bool m_ignoreBackupExitCode; | ||
295 | 312 | | |||
313 | bool m_fileOpen; | ||||
314 | QFileDevice::Permissions m_fmode; | ||||
315 | | ||||
316 | KMyMoneyApp::fileTypeE m_fileType; | ||||
317 | | ||||
296 | KProcess m_proc; | 318 | KProcess m_proc; | ||
297 | 319 | | |||
298 | /// A pointer to the view holding the tabs. | 320 | /// A pointer to the view holding the tabs. | ||
299 | KMyMoneyView *m_myMoneyView; | 321 | KMyMoneyView *m_myMoneyView; | ||
300 | 322 | | |||
301 | /// The URL of the file currently being edited when open. | 323 | /// The URL of the file currently being edited when open. | ||
302 | QUrl m_fileName; | 324 | QUrl m_fileName; | ||
303 | 325 | | |||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Line(s) | 372 | #endif | |||
355 | 377 | | |||
356 | WebConnect* m_webConnect; | 378 | WebConnect* m_webConnect; | ||
357 | 379 | | |||
358 | // methods | 380 | // methods | ||
359 | void consistencyCheck(bool alwaysDisplayResults); | 381 | void consistencyCheck(bool alwaysDisplayResults); | ||
360 | static void setThemedCSS(); | 382 | static void setThemedCSS(); | ||
361 | void copyConsistencyCheckResults(); | 383 | void copyConsistencyCheckResults(); | ||
362 | void saveConsistencyCheckResults(); | 384 | void saveConsistencyCheckResults(); | ||
385 | | ||||
386 | void checkAccountName(const MyMoneyAccount& _acc, const QString& name) const | ||||
387 | { | ||||
388 | auto file = MyMoneyFile::instance(); | ||||
389 | if (_acc.name() != name) { | ||||
390 | MyMoneyAccount acc(_acc); | ||||
391 | acc.setName(name); | ||||
392 | file->modifyAccount(acc); | ||||
393 | } | ||||
394 | } | ||||
395 | | ||||
396 | /** | ||||
397 | * This method updates names of currencies from file to localized names | ||||
398 | */ | ||||
399 | void updateCurrencyNames() | ||||
400 | { | ||||
401 | auto file = MyMoneyFile::instance(); | ||||
402 | MyMoneyFileTransaction ft; | ||||
403 | | ||||
404 | QList<MyMoneySecurity> storedCurrencies = MyMoneyFile::instance()->currencyList(); | ||||
405 | QList<MyMoneySecurity> availableCurrencies = MyMoneyFile::instance()->availableCurrencyList(); | ||||
406 | QStringList currencyIDs; | ||||
407 | | ||||
408 | foreach (auto currency, availableCurrencies) | ||||
409 | currencyIDs.append(currency.id()); | ||||
410 | | ||||
411 | try { | ||||
412 | foreach (auto currency, storedCurrencies) { | ||||
413 | int i = currencyIDs.indexOf(currency.id()); | ||||
414 | if (i != -1 && availableCurrencies.at(i).name() != currency.name()) { | ||||
415 | currency.setName(availableCurrencies.at(i).name()); | ||||
416 | file->modifyCurrency(currency); | ||||
417 | } | ||||
418 | } | ||||
419 | ft.commit(); | ||||
420 | } catch (const MyMoneyException &e) { | ||||
421 | qDebug("Error %s updating currency names", qPrintable(e.what())); | ||||
422 | } | ||||
423 | } | ||||
424 | | ||||
425 | void updateAccountNames() | ||||
426 | { | ||||
427 | // make sure we setup the name of the base accounts in translated form | ||||
428 | try { | ||||
429 | MyMoneyFileTransaction ft; | ||||
430 | const auto file = MyMoneyFile::instance(); | ||||
431 | checkAccountName(file->asset(), i18n("Asset")); | ||||
432 | checkAccountName(file->liability(), i18n("Liability")); | ||||
433 | checkAccountName(file->income(), i18n("Income")); | ||||
434 | checkAccountName(file->expense(), i18n("Expense")); | ||||
435 | checkAccountName(file->equity(), i18n("Equity")); | ||||
436 | ft.commit(); | ||||
437 | } catch (const MyMoneyException &) { | ||||
438 | } | ||||
439 | } | ||||
440 | | ||||
441 | void ungetString(QIODevice *qfile, char *buf, int len) | ||||
442 | { | ||||
443 | buf = &buf[len-1]; | ||||
444 | while (len--) { | ||||
445 | qfile->ungetChar(*buf--); | ||||
446 | } | ||||
447 | } | ||||
448 | | ||||
449 | bool applyFileFixes() | ||||
450 | { | ||||
451 | const auto blocked = MyMoneyFile::instance()->blockSignals(true); | ||||
452 | KSharedConfigPtr config = KSharedConfig::openConfig(); | ||||
453 | | ||||
454 | KConfigGroup grp = config->group("General Options"); | ||||
455 | | ||||
456 | // For debugging purposes, we can turn off the automatic fix manually | ||||
457 | // by setting the entry in kmymoneyrc to true | ||||
458 | grp = config->group("General Options"); | ||||
459 | if (grp.readEntry("SkipFix", false) != true) { | ||||
460 | MyMoneyFileTransaction ft; | ||||
461 | try { | ||||
462 | // Check if we have to modify the file before we allow to work with it | ||||
463 | auto s = MyMoneyFile::instance()->storage(); | ||||
464 | while (s->fileFixVersion() < s->currentFixVersion()) { | ||||
465 | qDebug("%s", qPrintable((QString("testing fileFixVersion %1 < %2").arg(s->fileFixVersion()).arg(s->currentFixVersion())))); | ||||
466 | switch (s->fileFixVersion()) { | ||||
467 | case 0: | ||||
468 | fixFile_0(); | ||||
tbaumgart: Isn't
```
q->d->fixFile_0();
```
the same as
```
fixFile_0();
```
? | |||||
469 | s->setFileFixVersion(1); | ||||
470 | break; | ||||
471 | | ||||
472 | case 1: | ||||
473 | fixFile_1(); | ||||
474 | s->setFileFixVersion(2); | ||||
475 | break; | ||||
476 | | ||||
477 | case 2: | ||||
478 | fixFile_2(); | ||||
479 | s->setFileFixVersion(3); | ||||
480 | break; | ||||
481 | | ||||
482 | case 3: | ||||
483 | fixFile_3(); | ||||
484 | s->setFileFixVersion(4); | ||||
485 | break; | ||||
486 | | ||||
487 | // add new levels above. Don't forget to increase currentFixVersion() for all | ||||
488 | // the storage backends this fix applies to | ||||
489 | default: | ||||
490 | throw MYMONEYEXCEPTION(i18n("Unknown fix level in input file")); | ||||
491 | } | ||||
492 | } | ||||
493 | ft.commit(); | ||||
494 | } catch (const MyMoneyException &) { | ||||
495 | MyMoneyFile::instance()->blockSignals(blocked); | ||||
496 | return false; | ||||
497 | } | ||||
498 | } else { | ||||
499 | qDebug("Skipping automatic transaction fix!"); | ||||
500 | } | ||||
501 | MyMoneyFile::instance()->blockSignals(blocked); | ||||
502 | return true; | ||||
503 | } | ||||
504 | | ||||
505 | void connectStorageToModels() | ||||
506 | { | ||||
507 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::objectAdded, | ||||
508 | Models::instance()->accountsModel(), &AccountsModel::slotObjectAdded); | ||||
509 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::objectModified, | ||||
510 | Models::instance()->accountsModel(), &AccountsModel::slotObjectModified); | ||||
511 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::objectRemoved, | ||||
512 | Models::instance()->accountsModel(), &AccountsModel::slotObjectRemoved); | ||||
513 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::balanceChanged, | ||||
514 | Models::instance()->accountsModel(), &AccountsModel::slotBalanceOrValueChanged); | ||||
515 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::valueChanged, | ||||
516 | Models::instance()->accountsModel(), &AccountsModel::slotBalanceOrValueChanged); | ||||
517 | | ||||
518 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::objectAdded, | ||||
519 | Models::instance()->institutionsModel(), &InstitutionsModel::slotObjectAdded); | ||||
520 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::objectModified, | ||||
521 | Models::instance()->institutionsModel(), &InstitutionsModel::slotObjectModified); | ||||
522 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::objectRemoved, | ||||
523 | Models::instance()->institutionsModel(), &InstitutionsModel::slotObjectRemoved); | ||||
524 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::balanceChanged, | ||||
525 | Models::instance()->institutionsModel(), &AccountsModel::slotBalanceOrValueChanged); | ||||
526 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::valueChanged, | ||||
527 | Models::instance()->institutionsModel(), &AccountsModel::slotBalanceOrValueChanged); | ||||
528 | | ||||
529 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::objectAdded, | ||||
530 | Models::instance()->equitiesModel(), &EquitiesModel::slotObjectAdded); | ||||
531 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::objectModified, | ||||
532 | Models::instance()->equitiesModel(), &EquitiesModel::slotObjectModified); | ||||
533 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::objectRemoved, | ||||
534 | Models::instance()->equitiesModel(), &EquitiesModel::slotObjectRemoved); | ||||
535 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::balanceChanged, | ||||
536 | Models::instance()->equitiesModel(), &EquitiesModel::slotBalanceOrValueChanged); | ||||
537 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::valueChanged, | ||||
538 | Models::instance()->equitiesModel(), &EquitiesModel::slotBalanceOrValueChanged); | ||||
539 | | ||||
540 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::objectAdded, | ||||
541 | Models::instance()->securitiesModel(), &SecuritiesModel::slotObjectAdded); | ||||
542 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::objectModified, | ||||
543 | Models::instance()->securitiesModel(), &SecuritiesModel::slotObjectModified); | ||||
544 | q->connect(MyMoneyFile::instance(), &MyMoneyFile::objectRemoved, | ||||
545 | Models::instance()->securitiesModel(), &SecuritiesModel::slotObjectRemoved); | ||||
546 | } | ||||
547 | | ||||
548 | void disconnectStorageFromModels() | ||||
549 | { | ||||
550 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::objectAdded, | ||||
551 | Models::instance()->accountsModel(), &AccountsModel::slotObjectAdded); | ||||
552 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::objectModified, | ||||
553 | Models::instance()->accountsModel(), &AccountsModel::slotObjectModified); | ||||
554 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::objectRemoved, | ||||
555 | Models::instance()->accountsModel(), &AccountsModel::slotObjectRemoved); | ||||
556 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::balanceChanged, | ||||
557 | Models::instance()->accountsModel(), &AccountsModel::slotBalanceOrValueChanged); | ||||
558 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::valueChanged, | ||||
559 | Models::instance()->accountsModel(), &AccountsModel::slotBalanceOrValueChanged); | ||||
560 | | ||||
561 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::objectAdded, | ||||
562 | Models::instance()->institutionsModel(), &InstitutionsModel::slotObjectAdded); | ||||
563 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::objectModified, | ||||
564 | Models::instance()->institutionsModel(), &InstitutionsModel::slotObjectModified); | ||||
565 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::objectRemoved, | ||||
566 | Models::instance()->institutionsModel(), &InstitutionsModel::slotObjectRemoved); | ||||
567 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::balanceChanged, | ||||
568 | Models::instance()->institutionsModel(), &AccountsModel::slotBalanceOrValueChanged); | ||||
569 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::valueChanged, | ||||
570 | Models::instance()->institutionsModel(), &AccountsModel::slotBalanceOrValueChanged); | ||||
571 | | ||||
572 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::objectAdded, | ||||
573 | Models::instance()->equitiesModel(), &EquitiesModel::slotObjectAdded); | ||||
574 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::objectModified, | ||||
575 | Models::instance()->equitiesModel(), &EquitiesModel::slotObjectModified); | ||||
576 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::objectRemoved, | ||||
577 | Models::instance()->equitiesModel(), &EquitiesModel::slotObjectRemoved); | ||||
578 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::balanceChanged, | ||||
579 | Models::instance()->equitiesModel(), &EquitiesModel::slotBalanceOrValueChanged); | ||||
580 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::valueChanged, | ||||
581 | Models::instance()->equitiesModel(), &EquitiesModel::slotBalanceOrValueChanged); | ||||
582 | | ||||
583 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::objectAdded, | ||||
584 | Models::instance()->securitiesModel(), &SecuritiesModel::slotObjectAdded); | ||||
585 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::objectModified, | ||||
586 | Models::instance()->securitiesModel(), &SecuritiesModel::slotObjectModified); | ||||
587 | q->disconnect(MyMoneyFile::instance(), &MyMoneyFile::objectRemoved, | ||||
588 | Models::instance()->securitiesModel(), &SecuritiesModel::slotObjectRemoved); | ||||
589 | } | ||||
590 | | ||||
591 | /** | ||||
592 | * This method is used after a file or database has been | ||||
593 | * read into storage, and performs various initialization tasks | ||||
594 | * | ||||
595 | * @retval true all went okay | ||||
596 | * @retval false an exception occurred during this process | ||||
597 | */ | ||||
598 | bool initializeStorage() | ||||
599 | { | ||||
600 | const auto blocked = MyMoneyFile::instance()->blockSignals(true); | ||||
601 | | ||||
602 | updateAccountNames(); | ||||
603 | updateCurrencyNames(); | ||||
604 | selectBaseCurrency(); | ||||
605 | | ||||
606 | // setup the standard precision | ||||
607 | AmountEdit::setStandardPrecision(MyMoneyMoney::denomToPrec(MyMoneyFile::instance()->baseCurrency().smallestAccountFraction())); | ||||
608 | KMyMoneyEdit::setStandardPrecision(MyMoneyMoney::denomToPrec(MyMoneyFile::instance()->baseCurrency().smallestAccountFraction())); | ||||
609 | | ||||
610 | if (!applyFileFixes()) | ||||
611 | return false; | ||||
612 | | ||||
613 | MyMoneyFile::instance()->blockSignals(blocked); | ||||
614 | | ||||
615 | emit q->kmmFilePlugin(KMyMoneyApp::postOpen); | ||||
616 | | ||||
617 | Models::instance()->fileOpened(); | ||||
618 | connectStorageToModels(); | ||||
619 | | ||||
620 | // inform everyone about new data | ||||
621 | MyMoneyFile::instance()->forceDataChanged(); | ||||
622 | | ||||
623 | q->slotCheckSchedules(); | ||||
624 | | ||||
625 | m_myMoneyView->slotFileOpened(); | ||||
626 | return true; | ||||
627 | } | ||||
628 | | ||||
629 | /** | ||||
630 | * This method attaches an empty storage object to the MyMoneyFile | ||||
631 | * object. It calls removeStorage() to remove a possibly attached | ||||
632 | * storage object. | ||||
633 | */ | ||||
634 | void newStorage() | ||||
635 | { | ||||
636 | removeStorage(); | ||||
637 | auto file = MyMoneyFile::instance(); | ||||
638 | file->attachStorage(new MyMoneyStorageMgr); | ||||
639 | } | ||||
640 | | ||||
641 | /** | ||||
642 | * This method removes an attached storage from the MyMoneyFile | ||||
643 | * object. | ||||
644 | */ | ||||
645 | void removeStorage() | ||||
646 | { | ||||
647 | auto file = MyMoneyFile::instance(); | ||||
648 | auto p = file->storage(); | ||||
649 | if (p) { | ||||
650 | file->detachStorage(p); | ||||
651 | delete p; | ||||
652 | } | ||||
653 | } | ||||
654 | | ||||
655 | /** | ||||
656 | * if no base currency is defined, start the dialog and force it to be set | ||||
657 | */ | ||||
658 | void selectBaseCurrency() | ||||
659 | { | ||||
660 | auto file = MyMoneyFile::instance(); | ||||
661 | | ||||
662 | // check if we have a base currency. If not, we need to select one | ||||
663 | QString baseId; | ||||
664 | try { | ||||
665 | baseId = MyMoneyFile::instance()->baseCurrency().id(); | ||||
666 | } catch (const MyMoneyException &e) { | ||||
667 | qDebug("%s", qPrintable(e.what())); | ||||
668 | } | ||||
669 | | ||||
670 | if (baseId.isEmpty()) { | ||||
671 | QPointer<KCurrencyEditDlg> dlg = new KCurrencyEditDlg(q); | ||||
672 | // connect(dlg, SIGNAL(selectBaseCurrency(MyMoneySecurity)), this, SLOT(slotSetBaseCurrency(MyMoneySecurity))); | ||||
673 | dlg->exec(); | ||||
674 | delete dlg; | ||||
675 | } | ||||
676 | | ||||
677 | try { | ||||
678 | baseId = MyMoneyFile::instance()->baseCurrency().id(); | ||||
679 | } catch (const MyMoneyException &e) { | ||||
680 | qDebug("%s", qPrintable(e.what())); | ||||
681 | } | ||||
682 | | ||||
683 | if (!baseId.isEmpty()) { | ||||
684 | // check that all accounts have a currency | ||||
685 | QList<MyMoneyAccount> list; | ||||
686 | file->accountList(list); | ||||
687 | QList<MyMoneyAccount>::Iterator it; | ||||
688 | | ||||
689 | // don't forget those standard accounts | ||||
690 | list << file->asset(); | ||||
691 | list << file->liability(); | ||||
692 | list << file->income(); | ||||
693 | list << file->expense(); | ||||
694 | list << file->equity(); | ||||
695 | | ||||
696 | | ||||
697 | for (it = list.begin(); it != list.end(); ++it) { | ||||
698 | QString cid; | ||||
699 | try { | ||||
700 | if (!(*it).currencyId().isEmpty() || (*it).currencyId().length() != 0) | ||||
701 | cid = MyMoneyFile::instance()->currency((*it).currencyId()).id(); | ||||
702 | } catch (const MyMoneyException& e) { | ||||
703 | qDebug() << QLatin1String("Account") << (*it).id() << (*it).name() << e.what(); | ||||
704 | } | ||||
705 | | ||||
706 | if (cid.isEmpty()) { | ||||
707 | (*it).setCurrencyId(baseId); | ||||
708 | MyMoneyFileTransaction ft; | ||||
709 | try { | ||||
710 | file->modifyAccount(*it); | ||||
711 | ft.commit(); | ||||
712 | } catch (const MyMoneyException &e) { | ||||
713 | qDebug("Unable to setup base currency in account %s (%s): %s", qPrintable((*it).name()), qPrintable((*it).id()), qPrintable(e.what())); | ||||
714 | } | ||||
715 | } | ||||
716 | } | ||||
717 | } | ||||
718 | } | ||||
719 | | ||||
720 | /** | ||||
721 | * Calls MyMoneyFile::readAllData which reads a MyMoneyFile into appropriate | ||||
722 | * data structures in memory. The return result is examined to make sure no | ||||
723 | * errors occurred whilst parsing. | ||||
724 | * | ||||
725 | * @param url The URL to read from. | ||||
726 | * If no protocol is specified, file:// is assumed. | ||||
727 | * | ||||
728 | * @return Whether the read was successful. | ||||
729 | */ | ||||
730 | bool openNondatabase(const QUrl &url) | ||||
731 | { | ||||
732 | if (!url.isValid()) | ||||
733 | throw MYMONEYEXCEPTION(QString::fromLatin1("Invalid URL %1").arg(qPrintable(url.url()))); | ||||
734 | | ||||
735 | QString fileName; | ||||
736 | auto downloadedFile = false; | ||||
737 | if (url.isLocalFile()) { | ||||
738 | fileName = url.toLocalFile(); | ||||
739 | } else { | ||||
740 | fileName = KMyMoneyUtils::downloadFile(url); | ||||
741 | downloadedFile = true; | ||||
742 | } | ||||
743 | | ||||
744 | if (!KMyMoneyUtils::fileExists(QUrl::fromLocalFile(fileName))) | ||||
745 | throw MYMONEYEXCEPTION(QString::fromLatin1("Error opening the file.\n" | ||||
746 | "Requested file: '%1'.\n" | ||||
747 | "Downloaded file: '%2'").arg(qPrintable(url.url()), fileName)); | ||||
748 | | ||||
749 | | ||||
750 | QFile file(fileName); | ||||
751 | if (!file.open(QIODevice::ReadOnly)) | ||||
752 | throw MYMONEYEXCEPTION(QString::fromLatin1("Cannot read the file: %1").arg(fileName)); | ||||
753 | | ||||
754 | QByteArray qbaFileHeader(2, '\0'); | ||||
755 | const auto sFileToShort = QString::fromLatin1("File %1 is too short.").arg(fileName); | ||||
756 | if (file.read(qbaFileHeader.data(), 2) != 2) | ||||
757 | throw MYMONEYEXCEPTION(sFileToShort); | ||||
758 | | ||||
759 | file.close(); | ||||
760 | | ||||
761 | // There's a problem with the KFilterDev and KGPGFile classes: | ||||
762 | // One supports the at(n) member but not ungetch() together with | ||||
763 | // read() and the other does not provide an at(n) method but | ||||
764 | // supports read() that considers the ungetch() buffer. QFile | ||||
765 | // supports everything so this is not a problem. We solve the problem | ||||
766 | // for now by keeping track of which method can be used. | ||||
767 | auto haveAt = true; | ||||
768 | auto isEncrypted = false; | ||||
769 | | ||||
770 | emit q->kmmFilePlugin(preOpen); | ||||
771 | | ||||
772 | QIODevice* qfile = nullptr; | ||||
773 | QString sFileHeader(qbaFileHeader); | ||||
774 | if (sFileHeader == QString("\037\213")) { // gzipped? | ||||
775 | qfile = new KCompressionDevice(fileName, COMPRESSION_TYPE); | ||||
776 | } else if (sFileHeader == QString("--") || // PGP ASCII armored? | ||||
777 | sFileHeader == QString("\205\001") || // PGP binary? | ||||
778 | sFileHeader == QString("\205\002")) { // PGP binary? | ||||
779 | if (KGPGFile::GPGAvailable()) { | ||||
780 | qfile = new KGPGFile(fileName); | ||||
781 | haveAt = false; | ||||
782 | isEncrypted = true; | ||||
783 | } else { | ||||
784 | throw MYMONEYEXCEPTION(QString::fromLatin1("%1").arg(i18n("GPG is not available for decryption of file <b>%1</b>", fileName))); | ||||
785 | } | ||||
786 | } else { | ||||
787 | // we can't use file directly, as we delete qfile later on | ||||
788 | qfile = new QFile(file.fileName()); | ||||
789 | } | ||||
790 | | ||||
791 | if (!qfile->open(QIODevice::ReadOnly)) { | ||||
792 | delete qfile; | ||||
793 | throw MYMONEYEXCEPTION(QString::fromLatin1("Cannot read the file: %1").arg(fileName)); | ||||
794 | } | ||||
795 | | ||||
796 | qbaFileHeader.resize(8); | ||||
797 | if (qfile->read(qbaFileHeader.data(), 8) != 8) | ||||
798 | throw MYMONEYEXCEPTION(sFileToShort); | ||||
799 | | ||||
800 | if (haveAt) | ||||
801 | qfile->seek(0); | ||||
802 | else | ||||
803 | ungetString(qfile, qbaFileHeader.data(), 8); | ||||
804 | | ||||
805 | // Ok, we got the first block of 8 bytes. Read in the two | ||||
806 | // unsigned long int's by preserving endianess. This is | ||||
807 | // achieved by reading them through a QDataStream object | ||||
808 | qint32 magic0, magic1; | ||||
809 | QDataStream s(&qbaFileHeader, QIODevice::ReadOnly); | ||||
810 | s >> magic0; | ||||
811 | s >> magic1; | ||||
812 | | ||||
813 | // If both magic numbers match (we actually read in the | ||||
814 | // text 'KMyMoney' then we assume a binary file and | ||||
815 | // construct a reader for it. Otherwise, we construct | ||||
816 | // an XML reader object. | ||||
817 | // | ||||
818 | // The expression magic0 < 30 is only used to create | ||||
819 | // a binary reader if we assume an old binary file. This | ||||
820 | // should be removed at some point. An alternative is to | ||||
821 | // check the beginning of the file against an pattern | ||||
822 | // of the XML file (e.g. '?<xml' ). | ||||
823 | if ((magic0 == MAGIC_0_50 && magic1 == MAGIC_0_51) || | ||||
824 | magic0 < 30) { | ||||
825 | // we do not support this file format anymore | ||||
826 | throw MYMONEYEXCEPTION(QString::fromLatin1("<qt>%1</qt>").arg(i18n("File <b>%1</b> contains the old binary format used by KMyMoney. Please use an older version of KMyMoney (0.8.x) that still supports this format to convert it to the new XML based format.", fileName))); | ||||
827 | } | ||||
828 | | ||||
829 | // Scan the first 70 bytes to see if we find something | ||||
830 | // we know. For now, we support our own XML format and | ||||
831 | // GNUCash XML format. If the file is smaller, then it | ||||
832 | // contains no valid data and we reject it anyway. | ||||
833 | qbaFileHeader.resize(70); | ||||
834 | if (qfile->read(qbaFileHeader.data(), 70) != 70) | ||||
835 | throw MYMONEYEXCEPTION(sFileToShort); | ||||
836 | | ||||
837 | if (haveAt) | ||||
838 | qfile->seek(0); | ||||
839 | else | ||||
840 | ungetString(qfile, qbaFileHeader.data(), 70); | ||||
841 | | ||||
842 | IMyMoneyOperationsFormat* pReader = nullptr; | ||||
843 | QRegExp kmyexp("<!DOCTYPE KMYMONEY-FILE>"); | ||||
844 | QRegExp gncexp("<gnc-v(\\d+)"); | ||||
845 | QByteArray txt(qbaFileHeader, 70); | ||||
846 | if (kmyexp.indexIn(txt) != -1) { | ||||
847 | pReader = new MyMoneyStorageXML; | ||||
848 | m_fileType = KMyMoneyApp::KmmXML; | ||||
849 | } else if (gncexp.indexIn(txt) != -1) { | ||||
850 | | ||||
Ah, here's a nice one: can't we add a method to the plugin that takes care of the detection? We pass the qbaFileHeader and the plugin tells us, if it is capable of reading the file (no matter how). This way, we can eliminate the GNC stuff here and move it into the plugin. tbaumgart: Ah, here's a nice one: can't we add a method to the plugin that takes care of the detection? We… | |||||
I think it's a good idea to have all GNC stuff in GNC plugin. I think, that instead of moulding every storage plugin to pReader we could only require MyMoneyStorageMgr filled up like in the case of SQL. I think it's not good to pass qbaFileHeader, because database can be just a url to connect to and not a physical file you can read through. I would like to divide that method further, shake off some more unneeded stuff and create XML storage plugin. Then we could have handlers of files in plugins which would be self contained units. I think the change you request could go in follow-up patches. wojnilowicz: I think it's a good idea to have all GNC stuff in GNC plugin.
I think, that instead of… | |||||
851 | for (const auto& plugin : m_plugins.storage) { | ||||
852 | if (plugin->formatName().compare(QLatin1String("GNC")) == 0) { | ||||
853 | pReader = plugin->reader(); | ||||
854 | break; | ||||
855 | } | ||||
856 | } | ||||
857 | if (!pReader) { | ||||
858 | KMessageBox::error(q, i18n("Couldn't find suitable plugin to read your storage.")); | ||||
859 | return false; | ||||
860 | } | ||||
861 | m_fileType = KMyMoneyApp::GncXML; | ||||
862 | } else { | ||||
863 | throw MYMONEYEXCEPTION(QString::fromLatin1("<qt>%1</qt>").arg(i18n("File <b>%1</b> contains an unknown file format.", fileName))); | ||||
864 | } | ||||
865 | | ||||
866 | // disconnect the current storga manager from the engine | ||||
867 | MyMoneyFile::instance()->detachStorage(); | ||||
868 | | ||||
869 | auto storage = new MyMoneyStorageMgr; | ||||
870 | pReader->setProgressCallback(&KMyMoneyApp::progressCallback); | ||||
871 | pReader->readFile(qfile, storage); | ||||
872 | pReader->setProgressCallback(0); | ||||
873 | delete pReader; | ||||
874 | | ||||
875 | qfile->close(); | ||||
876 | delete qfile; | ||||
877 | | ||||
878 | // if a temporary file was downloaded, then it will be removed | ||||
879 | // with the next call. Otherwise, it stays untouched on the local | ||||
880 | // filesystem. | ||||
881 | if (downloadedFile) | ||||
882 | QFile::remove(fileName); | ||||
883 | | ||||
884 | // things are finished, now we connect the storage to the engine | ||||
885 | // which forces a reload of the cache in the engine with those | ||||
886 | // objects that are cached | ||||
887 | MyMoneyFile::instance()->attachStorage(storage); | ||||
888 | | ||||
889 | // encapsulate transactions to the engine to be able to commit/rollback | ||||
890 | MyMoneyFileTransaction ft; | ||||
891 | // make sure we setup the encryption key correctly | ||||
892 | if (isEncrypted && MyMoneyFile::instance()->value("kmm-encryption-key").isEmpty()) | ||||
893 | MyMoneyFile::instance()->setValue("kmm-encryption-key", KMyMoneySettings::gpgRecipientList().join(",")); | ||||
894 | ft.commit(); | ||||
895 | return true; | ||||
896 | } | ||||
897 | | ||||
898 | /** | ||||
899 | * This method is called from readFile to open a database file which | ||||
900 | * is to be processed in 'proper' database mode, i.e. in-place updates | ||||
901 | * | ||||
902 | * @param dbaseURL pseudo-QUrl representation of database | ||||
903 | * | ||||
904 | * @retval true Database opened successfully | ||||
905 | * @retval false Could not open or read database | ||||
906 | */ | ||||
907 | bool openDatabase(const QUrl &url) | ||||
908 | { | ||||
909 | // open the database | ||||
910 | auto pStorage = MyMoneyFile::instance()->storage(); | ||||
911 | if (!pStorage) | ||||
912 | pStorage = new MyMoneyStorageMgr; | ||||
913 | | ||||
914 | auto rc = false; | ||||
915 | auto pluginFound = false; | ||||
916 | for (const auto& plugin : m_plugins.storage) { | ||||
917 | if (plugin->formatName().compare(QLatin1String("SQL")) == 0) { | ||||
918 | rc = plugin->open(pStorage, url); | ||||
919 | pluginFound = true; | ||||
920 | break; | ||||
921 | } | ||||
922 | } | ||||
923 | | ||||
924 | if(!pluginFound) | ||||
925 | KMessageBox::error(q, i18n("Couldn't find suitable plugin to read your storage.")); | ||||
926 | | ||||
927 | if(!rc) { | ||||
928 | removeStorage(); | ||||
929 | delete pStorage; | ||||
930 | return false; | ||||
931 | } | ||||
932 | | ||||
933 | if (pStorage) { | ||||
934 | MyMoneyFile::instance()->detachStorage(); | ||||
935 | MyMoneyFile::instance()->attachStorage(pStorage); | ||||
936 | } | ||||
937 | return true; | ||||
938 | } | ||||
939 | | ||||
940 | /** | ||||
941 | * Close the currently opened file and create an empty new file. | ||||
942 | * | ||||
943 | * @see MyMoneyFile | ||||
944 | */ | ||||
945 | void newFile() | ||||
946 | { | ||||
947 | closeFile(); | ||||
948 | m_fileType = KMyMoneyApp::KmmXML; // assume native type until saved | ||||
949 | m_fileOpen = true; | ||||
950 | } | ||||
951 | | ||||
952 | /** | ||||
953 | * Saves the data into permanent storage using the XML format. | ||||
954 | * | ||||
955 | * @param url The URL to save into. | ||||
956 | * If no protocol is specified, file:// is assumed. | ||||
957 | * @param keyList QString containing a comma separated list of keys | ||||
958 | * to be used for encryption. If @p keyList is empty, | ||||
959 | * the file will be saved unencrypted (the default) | ||||
960 | * | ||||
961 | * @retval false save operation failed | ||||
962 | * @retval true save operation was successful | ||||
963 | */ | ||||
964 | bool saveFile(const QUrl &url, const QString& keyList = QString()) | ||||
965 | { | ||||
966 | QString filename = url.path(); | ||||
967 | | ||||
968 | if (!m_fileOpen) { | ||||
969 | KMessageBox::error(q, i18n("Tried to access a file when it has not been opened")); | ||||
970 | return false; | ||||
971 | } | ||||
972 | | ||||
973 | emit q->kmmFilePlugin(KMyMoneyApp::preSave); | ||||
974 | std::unique_ptr<IMyMoneyOperationsFormat> storageWriter; | ||||
975 | | ||||
976 | // If this file ends in ".ANON.XML" then this should be written using the | ||||
977 | // anonymous writer. | ||||
978 | bool plaintext = filename.right(4).toLower() == ".xml"; | ||||
979 | if (filename.right(9).toLower() == ".anon.xml") | ||||
980 | storageWriter = std::make_unique<MyMoneyStorageANON>(); | ||||
981 | else | ||||
982 | storageWriter = std::make_unique<MyMoneyStorageXML>(); | ||||
983 | | ||||
984 | // actually, url should be the parameter to this function | ||||
985 | // but for now, this would involve too many changes | ||||
986 | bool rc = true; | ||||
987 | try { | ||||
988 | if (! url.isValid()) { | ||||
989 | throw MYMONEYEXCEPTION(i18n("Malformed URL '%1'", url.url())); | ||||
990 | } | ||||
991 | | ||||
992 | if (url.isLocalFile()) { | ||||
993 | filename = url.toLocalFile(); | ||||
994 | try { | ||||
995 | const unsigned int nbak = KMyMoneySettings::autoBackupCopies(); | ||||
996 | if (nbak) { | ||||
tbaumgart: Can't the
```
QString::fromLatin1("~")
```
be a
```
QLatin1String("~")
```
? | |||||
QStringLiteral is more appropriate here. Please check header file of KBackup::numberedBackupFile. wojnilowicz: QStringLiteral is more appropriate here. Please check header file of KBackup… | |||||
997 | KBackup::numberedBackupFile(filename, QString(), QStringLiteral("~"), nbak); | ||||
998 | } | ||||
999 | saveToLocalFile(filename, storageWriter.get(), plaintext, keyList); | ||||
1000 | } catch (const MyMoneyException &) { | ||||
1001 | throw MYMONEYEXCEPTION(i18n("Unable to write changes to '%1'", filename)); | ||||
1002 | } | ||||
1003 | } else { | ||||
1004 | QTemporaryFile tmpfile; | ||||
1005 | tmpfile.open(); // to obtain the name | ||||
1006 | tmpfile.close(); | ||||
1007 | saveToLocalFile(tmpfile.fileName(), storageWriter.get(), plaintext, keyList); | ||||
1008 | | ||||
1009 | Q_CONSTEXPR int permission = -1; | ||||
1010 | QFile file(tmpfile.fileName()); | ||||
1011 | file.open(QIODevice::ReadOnly); | ||||
1012 | KIO::StoredTransferJob *putjob = KIO::storedPut(file.readAll(), url, permission, KIO::JobFlag::Overwrite); | ||||
1013 | if (!putjob->exec()) { | ||||
1014 | throw MYMONEYEXCEPTION(i18n("Unable to upload to '%1'.<br />%2", url.toDisplayString(), putjob->errorString())); | ||||
1015 | } | ||||
1016 | file.close(); | ||||
1017 | } | ||||
1018 | m_fileType = KMyMoneyApp::KmmXML; | ||||
1019 | } catch (const MyMoneyException &e) { | ||||
1020 | KMessageBox::error(q, e.what()); | ||||
1021 | MyMoneyFile::instance()->setDirty(); | ||||
1022 | rc = false; | ||||
1023 | } | ||||
1024 | emit q->kmmFilePlugin(postSave); | ||||
1025 | return rc; | ||||
1026 | } | ||||
1027 | | ||||
1028 | /** | ||||
1029 | * This method is used by saveFile() to store the data | ||||
1030 | * either directly in the destination file if it is on | ||||
1031 | * the local file system or in a temporary file when | ||||
1032 | * the final destination is reached over a network | ||||
1033 | * protocol (e.g. FTP) | ||||
1034 | * | ||||
1035 | * @param localFile the name of the local file | ||||
1036 | * @param writer pointer to the formatter | ||||
1037 | * @param plaintext whether to override any compression & encryption settings | ||||
1038 | * @param keyList QString containing a comma separated list of keys to be used for encryption | ||||
1039 | * If @p keyList is empty, the file will be saved unencrypted | ||||
1040 | * | ||||
1041 | * @note This method will close the file when it is written. | ||||
1042 | */ | ||||
1043 | void saveToLocalFile(const QString& localFile, IMyMoneyOperationsFormat* pWriter, bool plaintext, const QString& keyList) | ||||
1044 | { | ||||
1045 | // Check GPG encryption | ||||
1046 | bool encryptFile = true; | ||||
1047 | bool encryptRecover = false; | ||||
1048 | if (!keyList.isEmpty()) { | ||||
1049 | if (!KGPGFile::GPGAvailable()) { | ||||
1050 | KMessageBox::sorry(q, i18n("GPG does not seem to be installed on your system. Please make sure that GPG can be found using the standard search path. This time, encryption is disabled."), i18n("GPG not found")); | ||||
1051 | encryptFile = false; | ||||
1052 | } else { | ||||
1053 | if (KMyMoneySettings::encryptRecover()) { | ||||
1054 | encryptRecover = true; | ||||
1055 | if (!KGPGFile::keyAvailable(QString(recoveryKeyId))) { | ||||
1056 | KMessageBox::sorry(q, i18n("<p>You have selected to encrypt your data also with the KMyMoney recover key, but the key with id</p><p><center><b>%1</b></center></p><p>has not been found in your keyring at this time. Please make sure to import this key into your keyring. You can find it on the <a href=\"https://kmymoney.org/\">KMyMoney web-site</a>. This time your data will not be encrypted with the KMyMoney recover key.</p>", QString(recoveryKeyId)), i18n("GPG Key not found")); | ||||
1057 | encryptRecover = false; | ||||
1058 | } | ||||
1059 | } | ||||
1060 | | ||||
1061 | for(const QString& key: keyList.split(',', QString::SkipEmptyParts)) { | ||||
1062 | if (!KGPGFile::keyAvailable(key)) { | ||||
1063 | KMessageBox::sorry(q, i18n("<p>You have specified to encrypt your data for the user-id</p><p><center><b>%1</b>.</center></p><p>Unfortunately, a valid key for this user-id was not found in your keyring. Please make sure to import a valid key for this user-id. This time, encryption is disabled.</p>", key), i18n("GPG Key not found")); | ||||
1064 | encryptFile = false; | ||||
1065 | break; | ||||
1066 | } | ||||
1067 | } | ||||
1068 | | ||||
1069 | if (encryptFile == true) { | ||||
1070 | QString msg = i18n("<p>You have configured to save your data in encrypted form using GPG. Make sure you understand that you might lose all your data if you encrypt it, but cannot decrypt it later on. If unsure, answer <b>No</b>.</p>"); | ||||
1071 | if (KMessageBox::questionYesNo(q, msg, i18n("Store GPG encrypted"), KStandardGuiItem::yes(), KStandardGuiItem::no(), "StoreEncrypted") == KMessageBox::No) { | ||||
1072 | encryptFile = false; | ||||
1073 | } | ||||
1074 | } | ||||
1075 | } | ||||
1076 | } | ||||
1077 | | ||||
1078 | | ||||
1079 | // Create a temporary file if needed | ||||
1080 | QString writeFile = localFile; | ||||
1081 | QTemporaryFile tmpFile; | ||||
1082 | if (QFile::exists(localFile)) { | ||||
1083 | tmpFile.open(); | ||||
1084 | writeFile = tmpFile.fileName(); | ||||
1085 | tmpFile.close(); | ||||
1086 | } | ||||
1087 | | ||||
1088 | /** | ||||
1089 | * @brief Automatically restore settings when scope is left | ||||
1090 | */ | ||||
1091 | struct restorePreviousSettingsHelper { | ||||
1092 | restorePreviousSettingsHelper() | ||||
1093 | : m_signalsWereBlocked{MyMoneyFile::instance()->signalsBlocked()} | ||||
1094 | { | ||||
1095 | MyMoneyFile::instance()->blockSignals(true); | ||||
1096 | } | ||||
1097 | | ||||
1098 | ~restorePreviousSettingsHelper() | ||||
1099 | { | ||||
1100 | MyMoneyFile::instance()->blockSignals(m_signalsWereBlocked); | ||||
1101 | } | ||||
1102 | const bool m_signalsWereBlocked; | ||||
1103 | } restoreHelper; | ||||
1104 | | ||||
1105 | MyMoneyFileTransaction ft; | ||||
1106 | MyMoneyFile::instance()->deletePair("kmm-encryption-key"); | ||||
1107 | std::unique_ptr<QIODevice> device; | ||||
1108 | | ||||
1109 | if (!keyList.isEmpty() && encryptFile && !plaintext) { | ||||
1110 | std::unique_ptr<KGPGFile> kgpg = std::unique_ptr<KGPGFile>(new KGPGFile{writeFile}); | ||||
1111 | if (kgpg) { | ||||
1112 | for(const QString& key: keyList.split(',', QString::SkipEmptyParts)) { | ||||
1113 | kgpg->addRecipient(key.toLatin1()); | ||||
1114 | } | ||||
1115 | | ||||
1116 | if (encryptRecover) { | ||||
1117 | kgpg->addRecipient(recoveryKeyId); | ||||
1118 | } | ||||
1119 | MyMoneyFile::instance()->setValue("kmm-encryption-key", keyList); | ||||
1120 | device = std::unique_ptr<decltype(device)::element_type>(kgpg.release()); | ||||
1121 | } | ||||
1122 | } else { | ||||
1123 | QFile *file = new QFile(writeFile); | ||||
1124 | // The second parameter of KCompressionDevice means that KCompressionDevice will delete the QFile object | ||||
1125 | device = std::unique_ptr<decltype(device)::element_type>(new KCompressionDevice{file, true, (plaintext) ? KCompressionDevice::None : COMPRESSION_TYPE}); | ||||
1126 | } | ||||
1127 | | ||||
1128 | ft.commit(); | ||||
1129 | | ||||
1130 | if (!device || !device->open(QIODevice::WriteOnly)) { | ||||
1131 | throw MYMONEYEXCEPTION(i18n("Unable to open file '%1' for writing.", localFile)); | ||||
1132 | } | ||||
1133 | | ||||
1134 | pWriter->setProgressCallback(&KMyMoneyApp::progressCallback); | ||||
1135 | pWriter->writeFile(device.get(), MyMoneyFile::instance()->storage()); | ||||
1136 | device->close(); | ||||
1137 | | ||||
1138 | // Check for errors if possible, only possible for KGPGFile | ||||
1139 | QFileDevice *fileDevice = qobject_cast<QFileDevice*>(device.get()); | ||||
1140 | if (fileDevice && fileDevice->error() != QFileDevice::NoError) { | ||||
1141 | throw MYMONEYEXCEPTION(i18n("Failure while writing to '%1'", localFile)); | ||||
1142 | } | ||||
1143 | | ||||
1144 | if (writeFile != localFile) { | ||||
1145 | // This simple comparison is possible because the strings are equal if no temporary file was created. | ||||
1146 | // If a temporary file was created, it is made in a way that the name is definitely different. So no | ||||
1147 | // symlinks etc. have to be evaluated. | ||||
1148 | if (!QFile::remove(localFile) || !QFile::rename(writeFile, localFile)) | ||||
1149 | throw MYMONEYEXCEPTION(i18n("Failure while writing to '%1'", localFile)); | ||||
1150 | } | ||||
1151 | QFile::setPermissions(localFile, m_fmode); | ||||
1152 | pWriter->setProgressCallback(0); | ||||
1153 | } | ||||
1154 | | ||||
1155 | /** | ||||
1156 | * Call this to see if the MyMoneyFile contains any unsaved data. | ||||
1157 | * | ||||
1158 | * @retval true if any data has been modified but not saved | ||||
1159 | * @retval false otherwise | ||||
1160 | */ | ||||
1161 | bool dirty() | ||||
1162 | { | ||||
1163 | if (!m_fileOpen) | ||||
1164 | return false; | ||||
1165 | | ||||
1166 | return MyMoneyFile::instance()->dirty(); | ||||
1167 | } | ||||
1168 | | ||||
1169 | | ||||
1170 | /* DO NOT ADD code to this function or any of it's called ones. | ||||
1171 | Instead, create a new function, fixFile_n, and modify the initializeStorage() | ||||
1172 | logic above to call it */ | ||||
1173 | | ||||
1174 | void fixFile_3() | ||||
1175 | { | ||||
1176 | // make sure each storage object contains a (unique) id | ||||
1177 | MyMoneyFile::instance()->storageId(); | ||||
1178 | } | ||||
1179 | | ||||
1180 | void fixFile_2() | ||||
1181 | { | ||||
1182 | auto file = MyMoneyFile::instance(); | ||||
1183 | MyMoneyTransactionFilter filter; | ||||
1184 | filter.setReportAllSplits(false); | ||||
1185 | QList<MyMoneyTransaction> transactionList; | ||||
1186 | file->transactionList(transactionList, filter); | ||||
1187 | | ||||
1188 | // scan the transactions and modify transactions with two splits | ||||
1189 | // which reference an account and a category to have the memo text | ||||
1190 | // of the account. | ||||
1191 | auto count = 0; | ||||
1192 | foreach (const auto transaction, transactionList) { | ||||
1193 | if (transaction.splitCount() == 2) { | ||||
1194 | QString accountId; | ||||
1195 | QString categoryId; | ||||
1196 | QString accountMemo; | ||||
1197 | QString categoryMemo; | ||||
1198 | foreach (const auto split, transaction.splits()) { | ||||
1199 | auto acc = file->account(split.accountId()); | ||||
1200 | if (acc.isIncomeExpense()) { | ||||
1201 | categoryId = split.id(); | ||||
1202 | categoryMemo = split.memo(); | ||||
1203 | } else { | ||||
1204 | accountId = split.id(); | ||||
1205 | accountMemo = split.memo(); | ||||
1206 | } | ||||
1207 | } | ||||
1208 | | ||||
1209 | if (!accountId.isEmpty() && !categoryId.isEmpty() | ||||
1210 | && accountMemo != categoryMemo) { | ||||
1211 | MyMoneyTransaction t(transaction); | ||||
1212 | MyMoneySplit s(t.splitById(categoryId)); | ||||
1213 | s.setMemo(accountMemo); | ||||
1214 | t.modifySplit(s); | ||||
1215 | file->modifyTransaction(t); | ||||
1216 | ++count; | ||||
1217 | } | ||||
1218 | } | ||||
1219 | } | ||||
1220 | qDebug("%d transactions fixed in fixFile_2", count); | ||||
1221 | } | ||||
1222 | | ||||
1223 | void fixFile_1() | ||||
1224 | { | ||||
1225 | // we need to fix reports. If the account filter list contains | ||||
1226 | // investment accounts, we need to add the stock accounts to the list | ||||
1227 | // as well if we don't have the expert mode enabled | ||||
1228 | if (!KMyMoneySettings::expertMode()) { | ||||
1229 | try { | ||||
1230 | QList<MyMoneyReport> reports = MyMoneyFile::instance()->reportList(); | ||||
1231 | QList<MyMoneyReport>::iterator it_r; | ||||
1232 | for (it_r = reports.begin(); it_r != reports.end(); ++it_r) { | ||||
1233 | QStringList list; | ||||
1234 | (*it_r).accounts(list); | ||||
1235 | QStringList missing; | ||||
1236 | QStringList::const_iterator it_a, it_b; | ||||
1237 | for (it_a = list.constBegin(); it_a != list.constEnd(); ++it_a) { | ||||
1238 | auto acc = MyMoneyFile::instance()->account(*it_a); | ||||
1239 | if (acc.accountType() == eMyMoney::Account::Type::Investment) { | ||||
1240 | foreach (const auto accountID, acc.accountList()) { | ||||
1241 | if (!list.contains(accountID)) { | ||||
1242 | missing.append(accountID); | ||||
1243 | } | ||||
1244 | } | ||||
1245 | } | ||||
1246 | } | ||||
1247 | if (!missing.isEmpty()) { | ||||
1248 | (*it_r).addAccount(missing); | ||||
1249 | MyMoneyFile::instance()->modifyReport(*it_r); | ||||
1250 | } | ||||
1251 | } | ||||
1252 | } catch (const MyMoneyException &) { | ||||
1253 | } | ||||
1254 | } | ||||
1255 | } | ||||
1256 | | ||||
1257 | #if 0 | ||||
1258 | if (!m_accountsView->allItemsSelected()) | ||||
1259 | { | ||||
1260 | // retrieve a list of selected accounts | ||||
1261 | QStringList list; | ||||
1262 | m_accountsView->selectedItems(list); | ||||
1263 | | ||||
1264 | // if we're not in expert mode, we need to make sure | ||||
1265 | // that all stock accounts for the selected investment | ||||
1266 | // account are also selected | ||||
1267 | if (!KMyMoneySettings::expertMode()) { | ||||
1268 | QStringList missing; | ||||
1269 | QStringList::const_iterator it_a, it_b; | ||||
1270 | for (it_a = list.begin(); it_a != list.end(); ++it_a) { | ||||
1271 | auto acc = MyMoneyFile::instance()->account(*it_a); | ||||
1272 | if (acc.accountType() == Account::Type::Investment) { | ||||
1273 | foreach (const auto accountID, acc.accountList()) { | ||||
1274 | if (!list.contains(accountID)) { | ||||
1275 | missing.append(accountID); | ||||
1276 | } | ||||
1277 | } | ||||
1278 | } | ||||
1279 | } | ||||
1280 | list += missing; | ||||
1281 | } | ||||
1282 | | ||||
1283 | m_filter.addAccount(list); | ||||
1284 | } | ||||
1285 | | ||||
1286 | #endif | ||||
1287 | | ||||
1288 | | ||||
1289 | | ||||
1290 | | ||||
1291 | | ||||
1292 | void fixFile_0() | ||||
1293 | { | ||||
1294 | /* (Ace) I am on a crusade against file fixups. Whenever we have to fix the | ||||
1295 | * file, it is really a warning. So I'm going to print a debug warning, and | ||||
1296 | * then go track them down when I see them to figure out how they got saved | ||||
1297 | * out needing fixing anyway. | ||||
1298 | */ | ||||
1299 | | ||||
1300 | auto file = MyMoneyFile::instance(); | ||||
1301 | QList<MyMoneyAccount> accountList; | ||||
1302 | file->accountList(accountList); | ||||
1303 | QList<MyMoneyAccount>::Iterator it_a; | ||||
1304 | QList<MyMoneySchedule> scheduleList = file->scheduleList(); | ||||
1305 | QList<MyMoneySchedule>::Iterator it_s; | ||||
1306 | | ||||
1307 | MyMoneyAccount equity = file->equity(); | ||||
1308 | MyMoneyAccount asset = file->asset(); | ||||
1309 | bool equityListEmpty = equity.accountList().count() == 0; | ||||
1310 | | ||||
1311 | for (it_a = accountList.begin(); it_a != accountList.end(); ++it_a) { | ||||
1312 | if ((*it_a).accountType() == eMyMoney::Account::Type::Loan | ||||
1313 | || (*it_a).accountType() == eMyMoney::Account::Type::AssetLoan) { | ||||
1314 | fixLoanAccount_0(*it_a); | ||||
1315 | } | ||||
1316 | // until early before 0.8 release, the equity account was not saved to | ||||
1317 | // the file. If we have an equity account with no sub-accounts but | ||||
1318 | // find and equity account that has equity() as it's parent, we reparent | ||||
1319 | // this account. Need to move it to asset() first, because otherwise | ||||
1320 | // MyMoneyFile::reparent would act as NOP. | ||||
1321 | if (equityListEmpty && (*it_a).accountType() == eMyMoney::Account::Type::Equity) { | ||||
1322 | if ((*it_a).parentAccountId() == equity.id()) { | ||||
1323 | auto acc = *it_a; | ||||
1324 | // tricky, force parent account to be empty so that we really | ||||
1325 | // can re-parent it | ||||
1326 | acc.setParentAccountId(QString()); | ||||
1327 | file->reparentAccount(acc, equity); | ||||
1328 | qDebug() << Q_FUNC_INFO << " fixed account " << acc.id() << " reparented to " << equity.id(); | ||||
1329 | } | ||||
1330 | } | ||||
1331 | } | ||||
1332 | | ||||
1333 | for (it_s = scheduleList.begin(); it_s != scheduleList.end(); ++it_s) { | ||||
1334 | fixSchedule_0(*it_s); | ||||
1335 | } | ||||
1336 | | ||||
1337 | fixTransactions_0(); | ||||
1338 | } | ||||
1339 | | ||||
1340 | void fixSchedule_0(MyMoneySchedule sched) | ||||
1341 | { | ||||
1342 | MyMoneyTransaction t = sched.transaction(); | ||||
1343 | QList<MyMoneySplit> splitList = t.splits(); | ||||
1344 | QList<MyMoneySplit>::ConstIterator it_s; | ||||
1345 | bool updated = false; | ||||
1346 | | ||||
1347 | try { | ||||
1348 | // Check if the splits contain valid data and set it to | ||||
1349 | // be valid. | ||||
1350 | for (it_s = splitList.constBegin(); it_s != splitList.constEnd(); ++it_s) { | ||||
1351 | // the first split is always the account on which this transaction operates | ||||
1352 | // and if the transaction commodity is not set, we take this | ||||
1353 | if (it_s == splitList.constBegin() && t.commodity().isEmpty()) { | ||||
1354 | qDebug() << Q_FUNC_INFO << " " << t.id() << " has no commodity"; | ||||
1355 | try { | ||||
1356 | auto acc = MyMoneyFile::instance()->account((*it_s).accountId()); | ||||
1357 | t.setCommodity(acc.currencyId()); | ||||
1358 | updated = true; | ||||
1359 | } catch (const MyMoneyException &) { | ||||
1360 | } | ||||
1361 | } | ||||
1362 | // make sure the account exists. If not, remove the split | ||||
1363 | try { | ||||
1364 | MyMoneyFile::instance()->account((*it_s).accountId()); | ||||
1365 | } catch (const MyMoneyException &) { | ||||
1366 | qDebug() << Q_FUNC_INFO << " " << sched.id() << " " << (*it_s).id() << " removed, because account '" << (*it_s).accountId() << "' does not exist."; | ||||
1367 | t.removeSplit(*it_s); | ||||
1368 | updated = true; | ||||
1369 | } | ||||
1370 | if ((*it_s).reconcileFlag() != eMyMoney::Split::State::NotReconciled) { | ||||
1371 | qDebug() << Q_FUNC_INFO << " " << sched.id() << " " << (*it_s).id() << " should be 'not reconciled'"; | ||||
1372 | MyMoneySplit split = *it_s; | ||||
1373 | split.setReconcileDate(QDate()); | ||||
1374 | split.setReconcileFlag(eMyMoney::Split::State::NotReconciled); | ||||
1375 | t.modifySplit(split); | ||||
1376 | updated = true; | ||||
1377 | } | ||||
1378 | // the schedule logic used to operate only on the value field. | ||||
1379 | // This is now obsolete. | ||||
1380 | if ((*it_s).shares().isZero() && !(*it_s).value().isZero()) { | ||||
1381 | MyMoneySplit split = *it_s; | ||||
1382 | split.setShares(split.value()); | ||||
1383 | t.modifySplit(split); | ||||
1384 | updated = true; | ||||
1385 | } | ||||
1386 | } | ||||
1387 | | ||||
1388 | // If there have been changes, update the schedule and | ||||
1389 | // the engine data. | ||||
1390 | if (updated) { | ||||
1391 | sched.setTransaction(t); | ||||
1392 | MyMoneyFile::instance()->modifySchedule(sched); | ||||
1393 | } | ||||
1394 | } catch (const MyMoneyException &e) { | ||||
1395 | qWarning("Unable to update broken schedule: %s", qPrintable(e.what())); | ||||
1396 | } | ||||
1397 | } | ||||
1398 | | ||||
1399 | void fixLoanAccount_0(MyMoneyAccount acc) | ||||
1400 | { | ||||
1401 | if (acc.value("final-payment").isEmpty() | ||||
1402 | || acc.value("term").isEmpty() | ||||
1403 | || acc.value("periodic-payment").isEmpty() | ||||
1404 | || acc.value("loan-amount").isEmpty() | ||||
1405 | || acc.value("interest-calculation").isEmpty() | ||||
1406 | || acc.value("schedule").isEmpty() | ||||
1407 | || acc.value("fixed-interest").isEmpty()) { | ||||
1408 | KMessageBox::information(q, | ||||
1409 | i18n("<p>The account \"%1\" was previously created as loan account but some information is missing.</p><p>The new loan wizard will be started to collect all relevant information.</p><p>Please use KMyMoney version 0.8.7 or later and earlier than version 0.9 to correct the problem.</p>" | ||||
1410 | , acc.name()), | ||||
1411 | i18n("Account problem")); | ||||
1412 | | ||||
1413 | throw MYMONEYEXCEPTION("Fix LoanAccount0 not supported anymore"); | ||||
1414 | } | ||||
1415 | } | ||||
1416 | | ||||
1417 | void fixTransactions_0() | ||||
1418 | { | ||||
1419 | auto file = MyMoneyFile::instance(); | ||||
1420 | | ||||
1421 | QList<MyMoneySchedule> scheduleList = file->scheduleList(); | ||||
1422 | MyMoneyTransactionFilter filter; | ||||
1423 | filter.setReportAllSplits(false); | ||||
1424 | QList<MyMoneyTransaction> transactionList; | ||||
1425 | file->transactionList(transactionList, filter); | ||||
1426 | | ||||
1427 | QList<MyMoneySchedule>::Iterator it_x; | ||||
1428 | QStringList interestAccounts; | ||||
1429 | | ||||
1430 | KMSTATUS(i18n("Fix transactions")); | ||||
1431 | q->slotStatusProgressBar(0, scheduleList.count() + transactionList.count()); | ||||
1432 | | ||||
1433 | int cnt = 0; | ||||
1434 | // scan the schedules to find interest accounts | ||||
1435 | for (it_x = scheduleList.begin(); it_x != scheduleList.end(); ++it_x) { | ||||
1436 | MyMoneyTransaction t = (*it_x).transaction(); | ||||
1437 | QList<MyMoneySplit>::ConstIterator it_s; | ||||
1438 | QStringList accounts; | ||||
1439 | bool hasDuplicateAccounts = false; | ||||
1440 | | ||||
1441 | foreach (const auto split, t.splits()) { | ||||
1442 | if (accounts.contains(split.accountId())) { | ||||
1443 | hasDuplicateAccounts = true; | ||||
1444 | qDebug() << Q_FUNC_INFO << " " << t.id() << " has multiple splits with account " << split.accountId(); | ||||
1445 | } else { | ||||
1446 | accounts << split.accountId(); | ||||
1447 | } | ||||
1448 | | ||||
1449 | if (split.action() == MyMoneySplit::actionName(eMyMoney::Split::Action::Interest)) { | ||||
1450 | if (interestAccounts.contains(split.accountId()) == 0) { | ||||
1451 | interestAccounts << split.accountId(); | ||||
1452 | } | ||||
1453 | } | ||||
1454 | } | ||||
1455 | if (hasDuplicateAccounts) { | ||||
1456 | fixDuplicateAccounts_0(t); | ||||
1457 | } | ||||
1458 | ++cnt; | ||||
1459 | if (!(cnt % 10)) | ||||
1460 | q->slotStatusProgressBar(cnt); | ||||
1461 | } | ||||
1462 | | ||||
1463 | // scan the transactions and modify loan transactions | ||||
1464 | for (auto& transaction : transactionList) { | ||||
1465 | QString defaultAction; | ||||
1466 | QList<MyMoneySplit> splits = transaction.splits(); | ||||
1467 | QStringList accounts; | ||||
1468 | | ||||
1469 | // check if base commodity is set. if not, set baseCurrency | ||||
1470 | if (transaction.commodity().isEmpty()) { | ||||
1471 | qDebug() << Q_FUNC_INFO << " " << transaction.id() << " has no base currency"; | ||||
1472 | transaction.setCommodity(file->baseCurrency().id()); | ||||
1473 | file->modifyTransaction(transaction); | ||||
1474 | } | ||||
1475 | | ||||
1476 | bool isLoan = false; | ||||
1477 | // Determine default action | ||||
1478 | if (transaction.splitCount() == 2) { | ||||
1479 | // check for transfer | ||||
1480 | int accountCount = 0; | ||||
1481 | MyMoneyMoney val; | ||||
1482 | foreach (const auto split, splits) { | ||||
1483 | auto acc = file->account(split.accountId()); | ||||
1484 | if (acc.accountGroup() == eMyMoney::Account::Type::Asset | ||||
1485 | || acc.accountGroup() == eMyMoney::Account::Type::Liability) { | ||||
1486 | val = split.value(); | ||||
1487 | accountCount++; | ||||
1488 | if (acc.accountType() == eMyMoney::Account::Type::Loan | ||||
1489 | || acc.accountType() == eMyMoney::Account::Type::AssetLoan) | ||||
1490 | isLoan = true; | ||||
1491 | } else | ||||
1492 | break; | ||||
1493 | } | ||||
1494 | if (accountCount == 2) { | ||||
1495 | if (isLoan) | ||||
1496 | defaultAction = MyMoneySplit::actionName(eMyMoney::Split::Action::Amortization); | ||||
1497 | else | ||||
1498 | defaultAction = MyMoneySplit::actionName(eMyMoney::Split::Action::Transfer); | ||||
1499 | } else { | ||||
1500 | if (val.isNegative()) | ||||
1501 | defaultAction = MyMoneySplit::actionName(eMyMoney::Split::Action::Withdrawal); | ||||
1502 | else | ||||
1503 | defaultAction = MyMoneySplit::actionName(eMyMoney::Split::Action::Deposit); | ||||
1504 | } | ||||
1505 | } | ||||
1506 | | ||||
1507 | isLoan = false; | ||||
1508 | foreach (const auto split, splits) { | ||||
1509 | auto acc = file->account(split.accountId()); | ||||
1510 | MyMoneyMoney val = split.value(); | ||||
1511 | if (acc.accountGroup() == eMyMoney::Account::Type::Asset | ||||
1512 | || acc.accountGroup() == eMyMoney::Account::Type::Liability) { | ||||
1513 | if (!val.isPositive()) { | ||||
1514 | defaultAction = MyMoneySplit::actionName(eMyMoney::Split::Action::Withdrawal); | ||||
1515 | break; | ||||
1516 | } else { | ||||
1517 | defaultAction = MyMoneySplit::actionName(eMyMoney::Split::Action::Deposit); | ||||
1518 | break; | ||||
1519 | } | ||||
1520 | } | ||||
1521 | } | ||||
1522 | | ||||
1523 | #if 0 | ||||
1524 | // Check for correct actions in transactions referencing credit cards | ||||
1525 | bool needModify = false; | ||||
1526 | // The action fields are actually not used anymore in the ledger view logic | ||||
1527 | // so we might as well skip this whole thing here! | ||||
1528 | for (it_s = splits.begin(); needModify == false && it_s != splits.end(); ++it_s) { | ||||
1529 | auto acc = file->account((*it_s).accountId()); | ||||
1530 | MyMoneyMoney val = (*it_s).value(); | ||||
1531 | if (acc.accountType() == Account::Type::CreditCard) { | ||||
1532 | if (val < 0 && (*it_s).action() != MyMoneySplit::actionName(eMyMoney::Split::Action::Withdrawal) && (*it_s).action() != MyMoneySplit::actionName(eMyMoney::Split::Action::Transfer)) | ||||
1533 | needModify = true; | ||||
1534 | if (val >= 0 && (*it_s).action() != MyMoneySplit::actionName(eMyMoney::Split::Action::Deposit) && (*it_s).action() != MyMoneySplit::actionName(eMyMoney::Split::Action::Transfer)) | ||||
1535 | needModify = true; | ||||
1536 | } | ||||
1537 | } | ||||
1538 | | ||||
1539 | // (Ace) Extended the #endif down to cover this conditional, because as-written | ||||
1540 | // it will ALWAYS be skipped. | ||||
1541 | | ||||
1542 | if (needModify == true) { | ||||
1543 | for (it_s = splits.begin(); it_s != splits.end(); ++it_s) { | ||||
1544 | (*it_s).setAction(defaultAction); | ||||
1545 | transaction.modifySplit(*it_s); | ||||
1546 | file->modifyTransaction(transaction); | ||||
1547 | } | ||||
1548 | splits = transaction.splits(); // update local copy | ||||
1549 | qDebug("Fixed credit card assignment in %s", transaction.id().data()); | ||||
1550 | } | ||||
1551 | #endif | ||||
1552 | | ||||
1553 | // Check for correct assignment of ActionInterest in all splits | ||||
1554 | // and check if there are any duplicates in this transactions | ||||
1555 | for (auto& split : splits) { | ||||
1556 | MyMoneyAccount splitAccount = file->account(split.accountId()); | ||||
1557 | if (!accounts.contains(split.accountId())) { | ||||
1558 | accounts << split.accountId(); | ||||
1559 | } | ||||
1560 | // if this split references an interest account, the action | ||||
1561 | // must be of type ActionInterest | ||||
1562 | if (interestAccounts.contains(split.accountId())) { | ||||
1563 | if (split.action() != MyMoneySplit::actionName(eMyMoney::Split::Action::Interest)) { | ||||
1564 | qDebug() << Q_FUNC_INFO << " " << transaction.id() << " contains an interest account (" << split.accountId() << ") but does not have ActionInterest"; | ||||
1565 | split.setAction(MyMoneySplit::actionName(eMyMoney::Split::Action::Interest)); | ||||
1566 | transaction.modifySplit(split); | ||||
1567 | file->modifyTransaction(transaction); | ||||
1568 | qDebug("Fixed interest action in %s", qPrintable(transaction.id())); | ||||
1569 | } | ||||
1570 | // if it does not reference an interest account, it must not be | ||||
1571 | // of type ActionInterest | ||||
1572 | } else { | ||||
1573 | if (split.action() == MyMoneySplit::actionName(eMyMoney::Split::Action::Interest)) { | ||||
1574 | qDebug() << Q_FUNC_INFO << " " << transaction.id() << " does not contain an interest account so it should not have ActionInterest"; | ||||
1575 | split.setAction(defaultAction); | ||||
1576 | transaction.modifySplit(split); | ||||
1577 | file->modifyTransaction(transaction); | ||||
1578 | qDebug("Fixed interest action in %s", qPrintable(transaction.id())); | ||||
1579 | } | ||||
1580 | } | ||||
1581 | | ||||
1582 | // check that for splits referencing an account that has | ||||
1583 | // the same currency as the transactions commodity the value | ||||
1584 | // and shares field are the same. | ||||
1585 | if (transaction.commodity() == splitAccount.currencyId() | ||||
1586 | && split.value() != split.shares()) { | ||||
1587 | qDebug() << Q_FUNC_INFO << " " << transaction.id() << " " << split.id() << " uses the transaction currency, but shares != value"; | ||||
1588 | split.setShares(split.value()); | ||||
1589 | transaction.modifySplit(split); | ||||
1590 | file->modifyTransaction(transaction); | ||||
1591 | } | ||||
1592 | | ||||
1593 | // fix the shares and values to have the correct fraction | ||||
1594 | if (!splitAccount.isInvest()) { | ||||
1595 | try { | ||||
1596 | int fract = splitAccount.fraction(); | ||||
1597 | if (split.shares() != split.shares().convert(fract)) { | ||||
1598 | qDebug("adjusting fraction in %s,%s", qPrintable(transaction.id()), qPrintable(split.id())); | ||||
1599 | split.setShares(split.shares().convert(fract)); | ||||
1600 | split.setValue(split.value().convert(fract)); | ||||
1601 | transaction.modifySplit(split); | ||||
1602 | file->modifyTransaction(transaction); | ||||
1603 | } | ||||
1604 | } catch (const MyMoneyException &) { | ||||
1605 | qDebug("Missing security '%s', split not altered", qPrintable(splitAccount.currencyId())); | ||||
1606 | } | ||||
1607 | } | ||||
1608 | } | ||||
1609 | | ||||
1610 | ++cnt; | ||||
1611 | if (!(cnt % 10)) | ||||
1612 | q->slotStatusProgressBar(cnt); | ||||
1613 | } | ||||
1614 | | ||||
1615 | q->slotStatusProgressBar(-1, -1); | ||||
1616 | } | ||||
1617 | | ||||
1618 | void fixDuplicateAccounts_0(MyMoneyTransaction& t) | ||||
1619 | { | ||||
1620 | qDebug("Duplicate account in transaction %s", qPrintable(t.id())); | ||||
1621 | } | ||||
1622 | | ||||
1623 | | ||||
1624 | | ||||
363 | }; | 1625 | }; | ||
364 | 1626 | | |||
365 | KMyMoneyApp::KMyMoneyApp(QWidget* parent) : | 1627 | KMyMoneyApp::KMyMoneyApp(QWidget* parent) : | ||
366 | KXmlGuiWindow(parent), | 1628 | KXmlGuiWindow(parent), | ||
367 | d(new Private(this)) | 1629 | d(new Private(this)) | ||
368 | { | 1630 | { | ||
369 | #ifdef KMM_DBUS | 1631 | #ifdef KMM_DBUS | ||
370 | new KmymoneyAdaptor(this); | 1632 | new KmymoneyAdaptor(this); | ||
Show All 32 Lines | 1664 | if (!themeName.isEmpty() && themeName != QLatin1Literal("system")) // if it isn't default theme then set it | |||
403 | QIcon::setThemeName(themeName); | 1665 | QIcon::setThemeName(themeName); | ||
404 | Icons::setIconThemeNames(QIcon::themeName()); // get whatever theme user ends up with and hope our icon names will fit that theme | 1666 | Icons::setIconThemeNames(QIcon::themeName()); // get whatever theme user ends up with and hope our icon names will fit that theme | ||
405 | } | 1667 | } | ||
406 | 1668 | | |||
407 | initStatusBar(); | 1669 | initStatusBar(); | ||
408 | pActions = initActions(); | 1670 | pActions = initActions(); | ||
409 | pMenus = initMenus(); | 1671 | pMenus = initMenus(); | ||
410 | 1672 | | |||
1673 | d->newStorage(); | ||||
411 | d->m_myMoneyView = new KMyMoneyView(this/*the global variable kmymoney is not yet assigned. So we pass it here*/); | 1674 | d->m_myMoneyView = new KMyMoneyView(this/*the global variable kmymoney is not yet assigned. So we pass it here*/); | ||
412 | layout->addWidget(d->m_myMoneyView, 10); | 1675 | layout->addWidget(d->m_myMoneyView, 10); | ||
413 | connect(d->m_myMoneyView, &KMyMoneyView::aboutToChangeView, this, &KMyMoneyApp::slotResetSelections); | 1676 | connect(d->m_myMoneyView, &KMyMoneyView::aboutToChangeView, this, &KMyMoneyApp::slotResetSelections); | ||
414 | connect(d->m_myMoneyView, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)), | 1677 | connect(d->m_myMoneyView, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)), | ||
415 | this, SLOT(slotUpdateActions())); | 1678 | this, SLOT(slotUpdateActions())); | ||
416 | 1679 | | |||
417 | connect(d->m_myMoneyView, &KMyMoneyView::statusMsg, this, &KMyMoneyApp::slotStatusMsg); | 1680 | connect(d->m_myMoneyView, &KMyMoneyView::statusMsg, this, &KMyMoneyApp::slotStatusMsg); | ||
418 | connect(d->m_myMoneyView, &KMyMoneyView::statusProgress, this, &KMyMoneyApp::slotStatusProgressBar); | 1681 | connect(d->m_myMoneyView, &KMyMoneyView::statusProgress, this, &KMyMoneyApp::slotStatusProgressBar); | ||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Line(s) | |||||
471 | slotDateChanged(); | 1734 | slotDateChanged(); | ||
472 | 1735 | | |||
473 | connect(this, SIGNAL(fileLoaded(QUrl)), onlineJobAdministration::instance(), SLOT(updateOnlineTaskProperties())); | 1736 | connect(this, SIGNAL(fileLoaded(QUrl)), onlineJobAdministration::instance(), SLOT(updateOnlineTaskProperties())); | ||
474 | 1737 | | |||
475 | } | 1738 | } | ||
476 | 1739 | | |||
477 | KMyMoneyApp::~KMyMoneyApp() | 1740 | KMyMoneyApp::~KMyMoneyApp() | ||
478 | { | 1741 | { | ||
1742 | d->removeStorage(); | ||||
479 | // delete cached objects since the are in the way | 1743 | // delete cached objects since the are in the way | ||
480 | // when unloading the plugins | 1744 | // when unloading the plugins | ||
481 | onlineJobAdministration::instance()->clearCaches(); | 1745 | onlineJobAdministration::instance()->clearCaches(); | ||
482 | 1746 | | |||
483 | // we need to unload all plugins before we destroy anything else | 1747 | // we need to unload all plugins before we destroy anything else | ||
484 | KMyMoneyPlugin::pluginHandling(KMyMoneyPlugin::Action::Unload, d->m_plugins, this, guiFactory()); | 1748 | KMyMoneyPlugin::pluginHandling(KMyMoneyPlugin::Action::Unload, d->m_plugins, this, guiFactory()); | ||
485 | 1749 | | |||
486 | delete d->m_searchDlg; | 1750 | delete d->m_searchDlg; | ||
▲ Show 20 Lines • Show All 514 Lines • ▼ Show 20 Line(s) | 2258 | { | |||
1001 | return ans; | 2265 | return ans; | ||
1002 | } | 2266 | } | ||
1003 | 2267 | | |||
1004 | bool KMyMoneyApp::queryClose() | 2268 | bool KMyMoneyApp::queryClose() | ||
1005 | { | 2269 | { | ||
1006 | if (!isReady()) | 2270 | if (!isReady()) | ||
1007 | return false; | 2271 | return false; | ||
1008 | 2272 | | |||
1009 | if (d->m_myMoneyView->dirty()) { | 2273 | if (d->dirty()) { | ||
1010 | int ans = askSaveOnClose(); | 2274 | int ans = askSaveOnClose(); | ||
1011 | 2275 | | |||
1012 | if (ans == KMessageBox::Cancel) | 2276 | if (ans == KMessageBox::Cancel) | ||
1013 | return false; | 2277 | return false; | ||
1014 | else if (ans == KMessageBox::Yes) { | 2278 | else if (ans == KMessageBox::Yes) { | ||
1015 | bool saved = slotFileSave(); | 2279 | bool saved = slotFileSave(); | ||
1016 | saveOptions(); | 2280 | saveOptions(); | ||
1017 | return saved; | 2281 | return saved; | ||
▲ Show 20 Lines • Show All 134 Lines • ▼ Show 20 Line(s) | |||||
1152 | } | 2416 | } | ||
1153 | 2417 | | |||
1154 | void KMyMoneyApp::slotFileNew() | 2418 | void KMyMoneyApp::slotFileNew() | ||
1155 | { | 2419 | { | ||
1156 | KMSTATUS(i18n("Creating new document...")); | 2420 | KMSTATUS(i18n("Creating new document...")); | ||
1157 | 2421 | | |||
1158 | slotFileClose(); | 2422 | slotFileClose(); | ||
1159 | 2423 | | |||
1160 | if (!d->m_myMoneyView->fileOpen()) { | 2424 | if (!d->m_fileOpen) { | ||
1161 | // next line required until we move all file handling out of KMyMoneyView | 2425 | // next line required until we move all file handling out of KMyMoneyView | ||
1162 | d->m_myMoneyView->newFile(); | 2426 | d->newFile(); | ||
1163 | 2427 | | |||
1164 | d->m_fileName = QUrl(); | 2428 | d->m_fileName = QUrl(); | ||
1165 | updateCaption(); | 2429 | updateCaption(); | ||
1166 | 2430 | | |||
1167 | NewUserWizard::Wizard *wizard = new NewUserWizard::Wizard(); | 2431 | NewUserWizard::Wizard *wizard = new NewUserWizard::Wizard(); | ||
1168 | 2432 | | |||
1169 | if (wizard->exec() == QDialog::Accepted) { | 2433 | if (wizard->exec() == QDialog::Accepted) { | ||
1170 | MyMoneyFileTransaction ft; | 2434 | MyMoneyFileTransaction ft; | ||
Show All 36 Lines | 2436 | try { | |||
1207 | ft.commit(); | 2471 | ft.commit(); | ||
1208 | KMyMoneySettings::setFirstTimeRun(false); | 2472 | KMyMoneySettings::setFirstTimeRun(false); | ||
1209 | 2473 | | |||
1210 | // FIXME This is a bit clumsy. We re-read the freshly | 2474 | // FIXME This is a bit clumsy. We re-read the freshly | ||
1211 | // created file to be able to run through all the | 2475 | // created file to be able to run through all the | ||
1212 | // fixup logic and then save it to keep the modified | 2476 | // fixup logic and then save it to keep the modified | ||
1213 | // flag off. | 2477 | // flag off. | ||
1214 | slotFileSave(); | 2478 | slotFileSave(); | ||
1215 | d->m_myMoneyView->readFile(d->m_fileName); | 2479 | if (d->openNondatabase(d->m_fileName)) { | ||
2480 | d->m_fileOpen = true; | ||||
2481 | d->initializeStorage(); | ||||
2482 | } | ||||
1216 | slotFileSave(); | 2483 | slotFileSave(); | ||
1217 | 2484 | | |||
1218 | // now keep the filename in the recent files used list | 2485 | // now keep the filename in the recent files used list | ||
1219 | //KRecentFilesAction *p = dynamic_cast<KRecentFilesAction*>(action(KStandardAction::name(KStandardAction::OpenRecent))); | 2486 | //KRecentFilesAction *p = dynamic_cast<KRecentFilesAction*>(action(KStandardAction::name(KStandardAction::OpenRecent))); | ||
1220 | //if(p) | 2487 | //if(p) | ||
1221 | d->m_recentFiles->addUrl(d->m_fileName); | 2488 | d->m_recentFiles->addUrl(d->m_fileName); | ||
1222 | writeLastUsedFile(d->m_fileName.url()); | 2489 | writeLastUsedFile(d->m_fileName.url()); | ||
1223 | 2490 | | |||
1224 | } catch (const MyMoneyException &) { | 2491 | } catch (const MyMoneyException &) { | ||
1225 | // next line required until we move all file handling out of KMyMoneyView | 2492 | // next line required until we move all file handling out of KMyMoneyView | ||
1226 | d->m_myMoneyView->closeFile(); | 2493 | d->closeFile(); | ||
1227 | } | 2494 | } | ||
1228 | if (wizard->startSettingsAfterFinished()) | 2495 | if (wizard->startSettingsAfterFinished()) | ||
1229 | slotSettings(); | 2496 | slotSettings(); | ||
1230 | } else { | 2497 | } else { | ||
1231 | // next line required until we move all file handling out of KMyMoneyView | 2498 | // next line required until we move all file handling out of KMyMoneyView | ||
1232 | d->m_myMoneyView->closeFile(); | 2499 | d->closeFile(); | ||
1233 | } | 2500 | } | ||
1234 | delete wizard; | 2501 | delete wizard; | ||
1235 | updateCaption(); | 2502 | updateCaption(); | ||
1236 | 2503 | | |||
1237 | emit fileLoaded(d->m_fileName); | 2504 | emit fileLoaded(d->m_fileName); | ||
1238 | } | 2505 | } | ||
1239 | } | 2506 | } | ||
1240 | 2507 | | |||
2508 | bool KMyMoneyApp::isDatabase() | ||||
2509 | { | ||||
2510 | return (d->m_fileOpen && ((d->m_fileType == KmmDb))); | ||||
2511 | } | ||||
2512 | | ||||
2513 | bool KMyMoneyApp::isNativeFile() | ||||
2514 | { | ||||
2515 | return (d->m_fileOpen && (d->m_fileType < MaxNativeFileType)); | ||||
Same here: the plugin should take care of adding it's own stuff that it supports. E.g. const QString fileExtension = plugin->fileExtension(); if (!fileExtension.isEmpty()) { fileExtensions.append(fileExtension); fileExtensions.append(QLatin1String(";;")); } No break, because it could have multiple plugins which can read their data file. tbaumgart: Same here: the plugin should take care of adding it's own stuff that it supports. E.g.
```… | |||||
wojnilowicz: I think it could be arranged. | |||||
2516 | } | ||||
2517 | | ||||
2518 | bool KMyMoneyApp::fileOpen() const | ||||
2519 | { | ||||
2520 | return d->m_fileOpen; | ||||
2521 | } | ||||
2522 | | ||||
1241 | // General open | 2523 | // General open | ||
1242 | void KMyMoneyApp::slotFileOpen() | 2524 | void KMyMoneyApp::slotFileOpen() | ||
1243 | { | 2525 | { | ||
1244 | KMSTATUS(i18n("Open a file.")); | 2526 | KMSTATUS(i18n("Open a file.")); | ||
1245 | 2527 | | |||
1246 | QString prevDir = readLastUsedDir(); | 2528 | QString prevDir = readLastUsedDir(); | ||
1247 | QPointer<QFileDialog> dialog = new QFileDialog(this, QString(), prevDir, | 2529 | QString fileExtensions; | ||
1248 | i18n("KMyMoney files (*.kmy *.xml);;All files")); | 2530 | fileExtensions.append(i18n("KMyMoney files (*.kmy *.xml)")); | ||
2531 | fileExtensions.append(QLatin1String(";;")); | ||||
2532 | | ||||
2533 | for (const auto& plugin : d->m_plugins.storage) { | ||||
2534 | const auto fileExtension = plugin->fileExtension(); | ||||
2535 | if (!fileExtension.isEmpty()) { | ||||
2536 | fileExtensions.append(fileExtension); | ||||
2537 | fileExtensions.append(QLatin1String(";;")); | ||||
2538 | } | ||||
2539 | } | ||||
2540 | fileExtensions.append(i18n("All files (*)")); | ||||
2541 | | ||||
2542 | QPointer<QFileDialog> dialog = new QFileDialog(this, QString(), prevDir, fileExtensions); | ||||
1249 | dialog->setFileMode(QFileDialog::ExistingFile); | 2543 | dialog->setFileMode(QFileDialog::ExistingFile); | ||
1250 | dialog->setAcceptMode(QFileDialog::AcceptOpen); | 2544 | dialog->setAcceptMode(QFileDialog::AcceptOpen); | ||
1251 | 2545 | | |||
1252 | if (dialog->exec() == QDialog::Accepted && dialog != nullptr) { | 2546 | if (dialog->exec() == QDialog::Accepted && dialog != nullptr) { | ||
1253 | slotFileOpenRecent(dialog->selectedUrls().first()); | 2547 | slotFileOpenRecent(dialog->selectedUrls().first()); | ||
1254 | } | 2548 | } | ||
1255 | delete dialog; | 2549 | delete dialog; | ||
1256 | } | 2550 | } | ||
1257 | 2551 | | |||
1258 | void KMyMoneyApp::slotOpenDatabase() | | |||
1259 | { | | |||
1260 | // KMSTATUS(i18n("Open a file.")); | | |||
1261 | // QPointer<KSelectDatabaseDlg> dialog = new KSelectDatabaseDlg(QIODevice::ReadWrite); | | |||
1262 | // if (!dialog->checkDrivers()) { | | |||
1263 | // delete dialog; | | |||
1264 | // return; | | |||
1265 | // } | | |||
1266 | | ||||
1267 | // if (dialog->exec() == QDialog::Accepted && dialog != 0) { | | |||
1268 | // slotFileOpenRecent(dialog->selectedURL()); | | |||
1269 | // } | | |||
1270 | // delete dialog; | | |||
1271 | } | | |||
1272 | | ||||
1273 | bool KMyMoneyApp::isImportableFile(const QUrl &url) | 2552 | bool KMyMoneyApp::isImportableFile(const QUrl &url) | ||
1274 | { | 2553 | { | ||
1275 | bool result = false; | 2554 | bool result = false; | ||
1276 | 2555 | | |||
1277 | // Iterate through the plugins and see if there's a loaded plugin who can handle it | 2556 | // Iterate through the plugins and see if there's a loaded plugin who can handle it | ||
1278 | QMap<QString, KMyMoneyPlugin::ImporterPlugin*>::const_iterator it_plugin = d->m_plugins.importer.constBegin(); | 2557 | QMap<QString, KMyMoneyPlugin::ImporterPlugin*>::const_iterator it_plugin = d->m_plugins.importer.constBegin(); | ||
1279 | while (it_plugin != d->m_plugins.importer.constEnd()) { | 2558 | while (it_plugin != d->m_plugins.importer.constEnd()) { | ||
1280 | if ((*it_plugin)->isMyFormat(url.path())) { | 2559 | if ((*it_plugin)->isMyFormat(url.path())) { | ||
Show All 32 Lines | 2583 | #ifdef KMM_DBUS | |||
1313 | } | 2592 | } | ||
1314 | #endif | 2593 | #endif | ||
1315 | return false; | 2594 | return false; | ||
1316 | } | 2595 | } | ||
1317 | 2596 | | |||
1318 | void KMyMoneyApp::slotFileOpenRecent(const QUrl &url) | 2597 | void KMyMoneyApp::slotFileOpenRecent(const QUrl &url) | ||
1319 | { | 2598 | { | ||
1320 | KMSTATUS(i18n("Loading file...")); | 2599 | KMSTATUS(i18n("Loading file...")); | ||
1321 | if (!isFileOpenedInAnotherInstance(url)) { | 2600 | if (isFileOpenedInAnotherInstance(url)) { | ||
1322 | QUrl newurl = url; | 2601 | KMessageBox::sorry(this, i18n("<p>File <b>%1</b> is already opened in another instance of KMyMoney</p>", url.toDisplayString(QUrl::PreferLocalFile)), i18n("Duplicate open")); | ||
1323 | if (newurl.scheme() == QLatin1String("sql") || KMyMoneyUtils::fileExists(newurl)) { | 2602 | return; | ||
2603 | } | ||||
2604 | | ||||
2605 | if (url.scheme() != QLatin1String("sql") && !KMyMoneyUtils::fileExists(url)) { | ||||
2606 | KMessageBox::sorry(this, i18n("<p><b>%1</b> is either an invalid filename or the file does not exist. You can open another file or create a new one.</p>", url.toDisplayString(QUrl::PreferLocalFile)), i18n("File not found")); | ||||
2607 | return; | ||||
2608 | } | ||||
2609 | | ||||
2610 | if (d->m_fileOpen) | ||||
1324 | slotFileClose(); | 2611 | slotFileClose(); | ||
1325 | if (!d->m_myMoneyView->fileOpen()) { | 2612 | | ||
2613 | if (d->m_fileOpen) | ||||
2614 | return; | ||||
2615 | | ||||
1326 | try { | 2616 | try { | ||
1327 | if (d->m_myMoneyView->readFile(newurl)) { | 2617 | auto isOpened = false; | ||
1328 | if ((d->m_myMoneyView->isNativeFile())) { | 2618 | if (url.scheme() == QLatin1String("sql")) | ||
1329 | d->m_fileName = newurl; | 2619 | isOpened = d->openDatabase(url); | ||
2620 | else | ||||
2621 | isOpened = d->openNondatabase(url); | ||||
2622 | | ||||
2623 | if (!isOpened) | ||||
2624 | return; | ||||
2625 | | ||||
2626 | d->m_fileOpen = true; | ||||
2627 | if (!d->initializeStorage()) { | ||||
2628 | d->m_fileOpen = false; | ||||
2629 | return; | ||||
2630 | } | ||||
2631 | | ||||
2632 | if (isNativeFile()) { | ||||
2633 | d->m_fileName = url; | ||||
1330 | updateCaption(); | 2634 | updateCaption(); | ||
1331 | d->m_recentFiles->addUrl(newurl); | 2635 | writeLastUsedFile(url.toDisplayString(QUrl::PreferLocalFile)); | ||
1332 | writeLastUsedFile(newurl.toDisplayString(QUrl::PreferLocalFile)); | 2636 | /* Dont't use url variable after KRecentFilesAction::addUrl | ||
2637 | * as it might delete it. | ||||
2638 | * More in API reference to this method | ||||
2639 | */ | ||||
2640 | d->m_recentFiles->addUrl(url); | ||||
1333 | } else { | 2641 | } else { | ||
1334 | d->m_fileName = QUrl(); // imported files have no filename | 2642 | d->m_fileName = QUrl(); // imported files have no filename | ||
1335 | } | 2643 | } | ||
1336 | // Check the schedules | 2644 | | ||
1337 | slotCheckSchedules(); | | |||
1338 | } | | |||
1339 | } catch (const MyMoneyException &e) { | 2645 | } catch (const MyMoneyException &e) { | ||
1340 | KMessageBox::sorry(this, i18n("Cannot open file as requested. Error was: %1", e.what())); | 2646 | KMessageBox::sorry(this, i18n("Cannot open file as requested. Error was: %1", e.what())); | ||
1341 | } | 2647 | } | ||
1342 | updateCaption(); | 2648 | updateCaption(); | ||
1343 | emit fileLoaded(d->m_fileName); | 2649 | emit fileLoaded(d->m_fileName); | ||
1344 | } else { | | |||
1345 | /*fileOpen failed - should we do something | | |||
1346 | or maybe fileOpen puts out the message... - it does for database*/ | | |||
1347 | } | | |||
1348 | } else { // newurl invalid | | |||
1349 | slotFileClose(); | | |||
1350 | KMessageBox::sorry(this, i18n("<p><b>%1</b> is either an invalid filename or the file does not exist. You can open another file or create a new one.</p>", url.toDisplayString(QUrl::PreferLocalFile)), i18n("File not found")); | | |||
1351 | } | | |||
1352 | } else { // isDuplicate | | |||
1353 | KMessageBox::sorry(this, i18n("<p>File <b>%1</b> is already opened in another instance of KMyMoney</p>", url.toDisplayString(QUrl::PreferLocalFile)), i18n("Duplicate open")); | | |||
1354 | } | | |||
1355 | } | 2650 | } | ||
1356 | 2651 | | |||
1357 | bool KMyMoneyApp::slotFileSave() | 2652 | bool KMyMoneyApp::slotFileSave() | ||
1358 | { | 2653 | { | ||
1359 | // if there's nothing changed, there's no need to save anything | 2654 | // if there's nothing changed, there's no need to save anything | ||
1360 | if (!d->m_myMoneyView->dirty()) | 2655 | if (!d->dirty()) | ||
1361 | return true; | 2656 | return true; | ||
1362 | 2657 | | |||
1363 | bool rc = false; | 2658 | bool rc = false; | ||
1364 | 2659 | | |||
1365 | KMSTATUS(i18n("Saving file...")); | 2660 | KMSTATUS(i18n("Saving file...")); | ||
1366 | 2661 | | |||
1367 | if (d->m_fileName.isEmpty()) | 2662 | if (d->m_fileName.isEmpty()) | ||
1368 | return slotFileSaveAs(); | 2663 | return slotFileSaveAs(); | ||
1369 | 2664 | | |||
1370 | d->consistencyCheck(false); | 2665 | d->consistencyCheck(false); | ||
1371 | 2666 | | |||
1372 | setEnabled(false); | 2667 | setEnabled(false); | ||
1373 | if (d->m_myMoneyView->isDatabase()) { | 2668 | if (isDatabase()) { | ||
1374 | auto pluginFound = false; | 2669 | auto pluginFound = false; | ||
1375 | for (const auto& plugin : d->m_plugins.storage) { | 2670 | for (const auto& plugin : d->m_plugins.storage) { | ||
1376 | if (plugin->formatName().compare(QLatin1String("SQL")) == 0) { | 2671 | if (plugin->formatName().compare(QLatin1String("SQL")) == 0) { | ||
1377 | rc = plugin->save(d->m_fileName); | 2672 | rc = plugin->save(d->m_fileName); | ||
1378 | pluginFound = true; | 2673 | pluginFound = true; | ||
1379 | break; | 2674 | break; | ||
1380 | } | 2675 | } | ||
1381 | } | 2676 | } | ||
1382 | if(!pluginFound) | 2677 | if(!pluginFound) | ||
1383 | KMessageBox::error(this, i18n("Couldn't find suitable plugin to save your storage.")); | 2678 | KMessageBox::error(this, i18n("Couldn't find suitable plugin to save your storage.")); | ||
1384 | } else { | 2679 | } else { | ||
1385 | rc = d->m_myMoneyView->saveFile(d->m_fileName, MyMoneyFile::instance()->value("kmm-encryption-key")); | 2680 | rc = d->saveFile(d->m_fileName, MyMoneyFile::instance()->value("kmm-encryption-key")); | ||
1386 | } | 2681 | } | ||
1387 | setEnabled(true); | 2682 | setEnabled(true); | ||
1388 | 2683 | | |||
1389 | d->m_autoSaveTimer->stop(); | 2684 | d->m_autoSaveTimer->stop(); | ||
1390 | 2685 | | |||
1391 | updateCaption(); | 2686 | updateCaption(); | ||
1392 | return rc; | 2687 | return rc; | ||
1393 | } | 2688 | } | ||
Show All 19 Lines | 2696 | if (KGPGFile::GPGAvailable() && KMyMoneySettings::writeDataEncrypted()) { | |||
1413 | } | 2708 | } | ||
1414 | delete dlg; | 2709 | delete dlg; | ||
1415 | if ((rc != QDialog::Accepted) || (dlg == 0)) { | 2710 | if ((rc != QDialog::Accepted) || (dlg == 0)) { | ||
1416 | return false; | 2711 | return false; | ||
1417 | } | 2712 | } | ||
1418 | } | 2713 | } | ||
1419 | 2714 | | |||
1420 | QString prevDir; // don't prompt file name if not a native file | 2715 | QString prevDir; // don't prompt file name if not a native file | ||
1421 | if (d->m_myMoneyView->isNativeFile()) | 2716 | if (isNativeFile()) | ||
1422 | prevDir = readLastUsedDir(); | 2717 | prevDir = readLastUsedDir(); | ||
1423 | 2718 | | |||
1424 | QPointer<QFileDialog> dlg = | 2719 | QPointer<QFileDialog> dlg = | ||
1425 | new QFileDialog(this, i18n("Save As"), prevDir, | 2720 | new QFileDialog(this, i18n("Save As"), prevDir, | ||
1426 | QString(QLatin1String("%2 (%1);;")).arg(QStringLiteral("*.kmy")).arg(i18nc("KMyMoney (Filefilter)", "KMyMoney files")) + | 2721 | QString(QLatin1String("%2 (%1);;")).arg(QStringLiteral("*.kmy")).arg(i18nc("KMyMoney (Filefilter)", "KMyMoney files")) + | ||
1427 | QString(QLatin1String("%2 (%1);;")).arg(QStringLiteral("*.xml")).arg(i18nc("XML (Filefilter)", "XML files")) + | 2722 | QString(QLatin1String("%2 (%1);;")).arg(QStringLiteral("*.xml")).arg(i18nc("XML (Filefilter)", "XML files")) + | ||
1428 | QString(QLatin1String("%2 (%1);;")).arg(QStringLiteral("*.anon.xml")).arg(i18nc("Anonymous (Filefilter)", "Anonymous files")) + | 2723 | QString(QLatin1String("%2 (%1);;")).arg(QStringLiteral("*.anon.xml")).arg(i18nc("Anonymous (Filefilter)", "Anonymous files")) + | ||
1429 | QString(QLatin1String("%2 (%1);;")).arg(QStringLiteral("*")).arg(i18nc("All files (Filefilter)", "All files"))); | 2724 | QString(QLatin1String("%2 (%1);;")).arg(QStringLiteral("*")).arg(i18nc("All files (Filefilter)", "All files"))); | ||
Show All 11 Lines | 2734 | if (!newName.endsWith(QLatin1String(".kmy"), Qt::CaseInsensitive) && | |||
1441 | newName.append(QLatin1String(".kmy")); | 2736 | newName.append(QLatin1String(".kmy")); | ||
1442 | newURL = QUrl::fromUserInput(newName); | 2737 | newURL = QUrl::fromUserInput(newName); | ||
1443 | d->m_recentFiles->addUrl(newURL); | 2738 | d->m_recentFiles->addUrl(newURL); | ||
1444 | 2739 | | |||
1445 | setEnabled(false); | 2740 | setEnabled(false); | ||
1446 | // If this is the anonymous file export, just save it, don't actually take the | 2741 | // If this is the anonymous file export, just save it, don't actually take the | ||
1447 | // name, or remember it! Don't even try to encrypt it | 2742 | // name, or remember it! Don't even try to encrypt it | ||
1448 | if (newName.endsWith(QLatin1String(".anon.xml"), Qt::CaseInsensitive)) | 2743 | if (newName.endsWith(QLatin1String(".anon.xml"), Qt::CaseInsensitive)) | ||
1449 | rc = d->m_myMoneyView->saveFile(newURL); | 2744 | rc = d->saveFile(newURL); | ||
1450 | else { | 2745 | else { | ||
1451 | d->m_fileName = newURL; | 2746 | d->m_fileName = newURL; | ||
1452 | QString encryptionKeys; | 2747 | QString encryptionKeys; | ||
1453 | QRegExp keyExp(".* \\((.*)\\)"); | 2748 | QRegExp keyExp(".* \\((.*)\\)"); | ||
1454 | if (keyExp.indexIn(selectedKeyName) != -1) { | 2749 | if (keyExp.indexIn(selectedKeyName) != -1) { | ||
1455 | encryptionKeys = keyExp.cap(1); | 2750 | encryptionKeys = keyExp.cap(1); | ||
1456 | if (!d->m_additionalGpgKeys.isEmpty()) { | 2751 | if (!d->m_additionalGpgKeys.isEmpty()) { | ||
1457 | if (!encryptionKeys.isEmpty()) | 2752 | if (!encryptionKeys.isEmpty()) | ||
1458 | encryptionKeys.append(QLatin1Char(',')); | 2753 | encryptionKeys.append(QLatin1Char(',')); | ||
1459 | encryptionKeys.append(d->m_additionalGpgKeys.join(QLatin1Char(','))); | 2754 | encryptionKeys.append(d->m_additionalGpgKeys.join(QLatin1Char(','))); | ||
1460 | } | 2755 | } | ||
1461 | } | 2756 | } | ||
1462 | rc = d->m_myMoneyView->saveFile(d->m_fileName, encryptionKeys); | 2757 | rc = d->saveFile(d->m_fileName, encryptionKeys); | ||
1463 | //write the directory used for this file as the default one for next time. | 2758 | //write the directory used for this file as the default one for next time. | ||
1464 | writeLastUsedDir(newURL.toDisplayString(QUrl::RemoveFilename | QUrl::PreferLocalFile | QUrl::StripTrailingSlash)); | 2759 | writeLastUsedDir(newURL.toDisplayString(QUrl::RemoveFilename | QUrl::PreferLocalFile | QUrl::StripTrailingSlash)); | ||
1465 | writeLastUsedFile(newName); | 2760 | writeLastUsedFile(newName); | ||
1466 | } | 2761 | } | ||
1467 | d->m_autoSaveTimer->stop(); | 2762 | d->m_autoSaveTimer->stop(); | ||
1468 | setEnabled(true); | 2763 | setEnabled(true); | ||
1469 | } | 2764 | } | ||
1470 | } | 2765 | } | ||
1471 | 2766 | | |||
1472 | delete dlg; | 2767 | delete dlg; | ||
1473 | updateCaption(); | 2768 | updateCaption(); | ||
1474 | return rc; | 2769 | return rc; | ||
1475 | } | 2770 | } | ||
1476 | 2771 | | |||
1477 | void KMyMoneyApp::slotSaveAsDatabase() | | |||
1478 | { | | |||
1479 | saveAsDatabase(); | | |||
1480 | } | | |||
1481 | | ||||
1482 | bool KMyMoneyApp::saveAsDatabase() | | |||
1483 | { | | |||
1484 | // bool rc = false; | | |||
1485 | // QUrl oldUrl; | | |||
1486 | // // in event of it being a database, ensure that all data is read into storage for saveas | | |||
1487 | // if (d->m_myMoneyView->isDatabase()) | | |||
1488 | // oldUrl = d->m_fileName.isEmpty() ? lastOpenedURL() : d->m_fileName; | | |||
1489 | | ||||
1490 | // KMSTATUS(i18n("Saving file to database...")); | | |||
1491 | // QPointer<KSelectDatabaseDlg> dialog = new KSelectDatabaseDlg(QIODevice::WriteOnly); | | |||
1492 | // QUrl url = oldUrl; | | |||
1493 | // if (!dialog->checkDrivers()) { | | |||
1494 | // delete dialog; | | |||
1495 | // return (false); | | |||
1496 | // } | | |||
1497 | | ||||
1498 | // while (oldUrl == url && dialog->exec() == QDialog::Accepted && dialog != 0) { | | |||
1499 | // url = dialog->selectedURL(); | | |||
1500 | // // If the protocol is SQL for the old and new, and the hostname and database names match | | |||
1501 | // // Let the user know that the current database cannot be saved on top of itself. | | |||
1502 | // if (url.scheme() == "sql" && oldUrl.scheme() == "sql" | | |||
1503 | // && oldUrl.host() == url.host() | | |||
1504 | // && QUrlQuery(oldUrl).queryItemValue("driver") == QUrlQuery(url).queryItemValue("driver") | | |||
1505 | // && oldUrl.path().right(oldUrl.path().length() - 1) == url.path().right(url.path().length() - 1)) { | | |||
1506 | // KMessageBox::sorry(this, i18n("Cannot save to current database.")); | | |||
1507 | // } else { | | |||
1508 | // try { | | |||
1509 | // rc = d->m_myMoneyView->saveAsDatabase(url); | | |||
1510 | // } catch (const MyMoneyException &e) { | | |||
1511 | // KMessageBox::sorry(this, i18n("Cannot save to current database: %1", e.what())); | | |||
1512 | // } | | |||
1513 | // } | | |||
1514 | // } | | |||
1515 | // delete dialog; | | |||
1516 | | ||||
1517 | // if (rc) { | | |||
1518 | // //KRecentFilesAction *p = dynamic_cast<KRecentFilesAction*>(action("file_open_recent")); | | |||
1519 | // //if(p) | | |||
1520 | // d->m_recentFiles->addUrl(url); | | |||
1521 | // writeLastUsedFile(url.toDisplayString(QUrl::PreferLocalFile)); | | |||
1522 | // } | | |||
1523 | // d->m_autoSaveTimer->stop(); | | |||
1524 | // updateCaption(); | | |||
1525 | // return rc; | | |||
1526 | return false; | | |||
1527 | } | | |||
1528 | | ||||
1529 | void KMyMoneyApp::slotFileCloseWindow() | 2772 | void KMyMoneyApp::slotFileCloseWindow() | ||
1530 | { | 2773 | { | ||
1531 | KMSTATUS(i18n("Closing window...")); | 2774 | KMSTATUS(i18n("Closing window...")); | ||
1532 | 2775 | | |||
1533 | if (d->m_myMoneyView->dirty()) { | 2776 | if (d->dirty()) { | ||
1534 | int answer = askSaveOnClose(); | 2777 | int answer = askSaveOnClose(); | ||
1535 | if (answer == KMessageBox::Cancel) | 2778 | if (answer == KMessageBox::Cancel) | ||
1536 | return; | 2779 | return; | ||
1537 | else if (answer == KMessageBox::Yes) | 2780 | else if (answer == KMessageBox::Yes) | ||
1538 | slotFileSave(); | 2781 | slotFileSave(); | ||
1539 | } | 2782 | } | ||
1540 | close(); | 2783 | close(); | ||
1541 | } | 2784 | } | ||
1542 | 2785 | | |||
1543 | void KMyMoneyApp::slotFileClose() | 2786 | void KMyMoneyApp::slotFileClose() | ||
1544 | { | 2787 | { | ||
1545 | bool okToSelect = true; | 2788 | bool okToSelect = true; | ||
1546 | 2789 | | |||
1547 | // check if transaction editor is open and ask user what he wants to do | 2790 | // check if transaction editor is open and ask user what he wants to do | ||
1548 | // slotTransactionsCancelOrEnter(okToSelect); | 2791 | // slotTransactionsCancelOrEnter(okToSelect); | ||
1549 | 2792 | | |||
1550 | if (!okToSelect) | 2793 | if (!okToSelect) | ||
1551 | return; | 2794 | return; | ||
1552 | 2795 | | |||
1553 | // no update status here, as we might delete the status too early. | 2796 | // no update status here, as we might delete the status too early. | ||
1554 | if (d->m_myMoneyView->dirty()) { | 2797 | if (d->dirty()) { | ||
1555 | int answer = askSaveOnClose(); | 2798 | int answer = askSaveOnClose(); | ||
1556 | if (answer == KMessageBox::Cancel) | 2799 | if (answer == KMessageBox::Cancel) | ||
1557 | return; | 2800 | return; | ||
1558 | else if (answer == KMessageBox::Yes) | 2801 | else if (answer == KMessageBox::Yes) | ||
1559 | slotFileSave(); | 2802 | slotFileSave(); | ||
1560 | } | 2803 | } | ||
1561 | 2804 | | |||
1562 | d->closeFile(); | 2805 | d->closeFile(); | ||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Line(s) | |||||
1610 | { | 2853 | { | ||
1611 | KMyMoneySettings::setShowAllAccounts(pActions[Action::ViewShowAll]->isChecked()); | 2854 | KMyMoneySettings::setShowAllAccounts(pActions[Action::ViewShowAll]->isChecked()); | ||
1612 | d->m_myMoneyView->slotRefreshViews(); | 2855 | d->m_myMoneyView->slotRefreshViews(); | ||
1613 | } | 2856 | } | ||
1614 | 2857 | | |||
1615 | #ifdef KMM_DEBUG | 2858 | #ifdef KMM_DEBUG | ||
1616 | void KMyMoneyApp::slotFileFileInfo() | 2859 | void KMyMoneyApp::slotFileFileInfo() | ||
1617 | { | 2860 | { | ||
1618 | if (!d->m_myMoneyView->fileOpen()) { | 2861 | if (!d->m_fileOpen) { | ||
1619 | KMessageBox::information(this, i18n("No KMyMoneyFile open")); | 2862 | KMessageBox::information(this, i18n("No KMyMoneyFile open")); | ||
1620 | return; | 2863 | return; | ||
1621 | } | 2864 | } | ||
1622 | 2865 | | |||
1623 | QFile g("kmymoney.dump"); | 2866 | QFile g("kmymoney.dump"); | ||
1624 | g.open(QIODevice::WriteOnly); | 2867 | g.open(QIODevice::WriteOnly); | ||
1625 | QDataStream st(&g); | 2868 | QDataStream st(&g); | ||
1626 | MyMoneyStorageDump dumper; | 2869 | MyMoneyStorageDump dumper; | ||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Line(s) | 2947 | { | |||
1705 | if (!msg.isEmpty()) | 2948 | if (!msg.isEmpty()) | ||
1706 | kmymoney->slotStatusMsg(msg); | 2949 | kmymoney->slotStatusMsg(msg); | ||
1707 | 2950 | | |||
1708 | kmymoney->slotStatusProgressBar(current, total); | 2951 | kmymoney->slotStatusProgressBar(current, total); | ||
1709 | } | 2952 | } | ||
1710 | 2953 | | |||
1711 | void KMyMoneyApp::slotFileViewPersonal() | 2954 | void KMyMoneyApp::slotFileViewPersonal() | ||
1712 | { | 2955 | { | ||
1713 | if (!d->m_myMoneyView->fileOpen()) { | 2956 | if (!d->m_fileOpen) { | ||
1714 | KMessageBox::information(this, i18n("No KMyMoneyFile open")); | 2957 | KMessageBox::information(this, i18n("No KMyMoneyFile open")); | ||
1715 | return; | 2958 | return; | ||
1716 | } | 2959 | } | ||
1717 | 2960 | | |||
1718 | KMSTATUS(i18n("Viewing personal data...")); | 2961 | KMSTATUS(i18n("Viewing personal data...")); | ||
1719 | 2962 | | |||
1720 | MyMoneyFile* file = MyMoneyFile::instance(); | 2963 | MyMoneyFile* file = MyMoneyFile::instance(); | ||
1721 | MyMoneyPayee user = file->user(); | 2964 | MyMoneyPayee user = file->user(); | ||
▲ Show 20 Lines • Show All 153 Lines • ▼ Show 20 Line(s) | 3107 | // MyMoneyStorageSql::setStartDate(KMyMoneySettings::startDate().date()); | |||
1875 | d->m_autoSaveEnabled = KMyMoneySettings::autoSaveFile(); | 3118 | d->m_autoSaveEnabled = KMyMoneySettings::autoSaveFile(); | ||
1876 | d->m_autoSavePeriod = KMyMoneySettings::autoSavePeriod(); | 3119 | d->m_autoSavePeriod = KMyMoneySettings::autoSavePeriod(); | ||
1877 | 3120 | | |||
1878 | // stop timer if turned off but running | 3121 | // stop timer if turned off but running | ||
1879 | if (d->m_autoSaveTimer->isActive() && !d->m_autoSaveEnabled) { | 3122 | if (d->m_autoSaveTimer->isActive() && !d->m_autoSaveEnabled) { | ||
1880 | d->m_autoSaveTimer->stop(); | 3123 | d->m_autoSaveTimer->stop(); | ||
1881 | } | 3124 | } | ||
1882 | // start timer if turned on and needed but not running | 3125 | // start timer if turned on and needed but not running | ||
1883 | if (!d->m_autoSaveTimer->isActive() && d->m_autoSaveEnabled && d->m_myMoneyView->dirty()) { | 3126 | if (!d->m_autoSaveTimer->isActive() && d->m_autoSaveEnabled && d->dirty()) { | ||
1884 | d->m_autoSaveTimer->setSingleShot(true); | 3127 | d->m_autoSaveTimer->setSingleShot(true); | ||
1885 | d->m_autoSaveTimer->start(d->m_autoSavePeriod * 60 * 1000); | 3128 | d->m_autoSaveTimer->start(d->m_autoSavePeriod * 60 * 1000); | ||
1886 | } | 3129 | } | ||
1887 | 3130 | | |||
1888 | d->setThemedCSS(); | 3131 | d->setThemedCSS(); | ||
1889 | 3132 | | |||
1890 | // check if the recovery key is still valid or expires soon | 3133 | // check if the recovery key is still valid or expires soon | ||
1891 | 3134 | | |||
1892 | if (KMyMoneySettings::writeDataEncrypted() && KMyMoneySettings::encryptRecover()) { | 3135 | if (KMyMoneySettings::writeDataEncrypted() && KMyMoneySettings::encryptRecover()) { | ||
1893 | if (KGPGFile::GPGAvailable()) { | 3136 | if (KGPGFile::GPGAvailable()) { | ||
1894 | KGPGFile file; | 3137 | KGPGFile file; | ||
1895 | QDateTime expirationDate = file.keyExpires(QLatin1String(recoveryKeyId)); | 3138 | QDateTime expirationDate = file.keyExpires(QLatin1String(recoveryKeyId2)); | ||
1896 | if (expirationDate.isValid() && QDateTime::currentDateTime().daysTo(expirationDate) <= RECOVER_KEY_EXPIRATION_WARNING) { | 3139 | if (expirationDate.isValid() && QDateTime::currentDateTime().daysTo(expirationDate) <= RECOVER_KEY_EXPIRATION_WARNING) { | ||
1897 | bool skipMessage = false; | 3140 | bool skipMessage = false; | ||
1898 | 3141 | | |||
1899 | //get global config object for our app. | 3142 | //get global config object for our app. | ||
1900 | KSharedConfigPtr kconfig = KSharedConfig::openConfig(); | 3143 | KSharedConfigPtr kconfig = KSharedConfig::openConfig(); | ||
1901 | KConfigGroup grp; | 3144 | KConfigGroup grp; | ||
1902 | QDate lastWarned; | 3145 | QDate lastWarned; | ||
1903 | if (kconfig) { | 3146 | if (kconfig) { | ||
Show All 12 Lines | |||||
1916 | } | 3159 | } | ||
1917 | } | 3160 | } | ||
1918 | } | 3161 | } | ||
1919 | } | 3162 | } | ||
1920 | 3163 | | |||
1921 | void KMyMoneyApp::slotBackupFile() | 3164 | void KMyMoneyApp::slotBackupFile() | ||
1922 | { | 3165 | { | ||
1923 | // Save the file first so isLocalFile() works | 3166 | // Save the file first so isLocalFile() works | ||
1924 | if (d->m_myMoneyView && d->m_myMoneyView->dirty()) | 3167 | if (d->m_myMoneyView && d->dirty()) | ||
1925 | 3168 | | |||
1926 | { | 3169 | { | ||
1927 | if (KMessageBox::questionYesNo(this, i18n("The file must be saved first " | 3170 | if (KMessageBox::questionYesNo(this, i18n("The file must be saved first " | ||
1928 | "before it can be backed up. Do you want to continue?")) == KMessageBox::No) { | 3171 | "before it can be backed up. Do you want to continue?")) == KMessageBox::No) { | ||
1929 | return; | 3172 | return; | ||
1930 | 3173 | | |||
1931 | } | 3174 | } | ||
1932 | 3175 | | |||
▲ Show 20 Lines • Show All 533 Lines • ▼ Show 20 Line(s) | |||||
2466 | } | 3709 | } | ||
2467 | 3710 | | |||
2468 | void KMyMoneyApp::updateCaption(bool skipActions) | 3711 | void KMyMoneyApp::updateCaption(bool skipActions) | ||
2469 | { | 3712 | { | ||
2470 | QString caption; | 3713 | QString caption; | ||
2471 | 3714 | | |||
2472 | caption = d->m_fileName.fileName(); | 3715 | caption = d->m_fileName.fileName(); | ||
2473 | 3716 | | |||
2474 | if (caption.isEmpty() && d->m_myMoneyView && d->m_myMoneyView->fileOpen()) | 3717 | if (caption.isEmpty() && d->m_myMoneyView && d->m_fileOpen) | ||
2475 | caption = i18n("Untitled"); | 3718 | caption = i18n("Untitled"); | ||
2476 | 3719 | | |||
2477 | // MyMoneyFile::instance()->dirty() throws an exception, if | 3720 | // MyMoneyFile::instance()->dirty() throws an exception, if | ||
2478 | // there's no storage object available. In this case, we | 3721 | // there's no storage object available. In this case, we | ||
2479 | // assume that the storage object is not changed. Actually, | 3722 | // assume that the storage object is not changed. Actually, | ||
2480 | // this can only happen if we are newly created early on. | 3723 | // this can only happen if we are newly created early on. | ||
2481 | bool modified; | 3724 | bool modified; | ||
2482 | try { | 3725 | try { | ||
2483 | modified = MyMoneyFile::instance()->dirty(); | 3726 | modified = MyMoneyFile::instance()->dirty(); | ||
2484 | } catch (const MyMoneyException &) { | 3727 | } catch (const MyMoneyException &) { | ||
2485 | modified = false; | 3728 | modified = false; | ||
2486 | skipActions = true; | 3729 | skipActions = true; | ||
2487 | } | 3730 | } | ||
2488 | 3731 | | |||
2489 | #ifdef KMM_DEBUG | 3732 | #ifdef KMM_DEBUG | ||
2490 | caption += QString(" (%1 x %2)").arg(width()).arg(height()); | 3733 | caption += QString(" (%1 x %2)").arg(width()).arg(height()); | ||
2491 | #endif | 3734 | #endif | ||
2492 | 3735 | | |||
2493 | setCaption(caption, modified); | 3736 | setCaption(caption, modified); | ||
2494 | 3737 | | |||
2495 | if (!skipActions) { | 3738 | if (!skipActions) { | ||
2496 | d->m_myMoneyView->enableViewsIfFileOpen(); | 3739 | d->m_myMoneyView->enableViewsIfFileOpen(d->m_fileOpen); | ||
2497 | slotUpdateActions(); | 3740 | slotUpdateActions(); | ||
2498 | } | 3741 | } | ||
2499 | } | 3742 | } | ||
2500 | 3743 | | |||
2501 | void KMyMoneyApp::slotUpdateActions() | 3744 | void KMyMoneyApp::slotUpdateActions() | ||
2502 | { | 3745 | { | ||
2503 | const auto file = MyMoneyFile::instance(); | 3746 | const auto file = MyMoneyFile::instance(); | ||
2504 | const bool fileOpen = d->m_myMoneyView->fileOpen(); | 3747 | const bool fileOpen = d->m_fileOpen; | ||
2505 | const bool modified = file->dirty(); | 3748 | const bool modified = file->dirty(); | ||
2506 | // const bool importRunning = (d->m_smtReader != 0); | 3749 | // const bool importRunning = (d->m_smtReader != 0); | ||
2507 | auto aC = actionCollection(); | 3750 | auto aC = actionCollection(); | ||
2508 | 3751 | | |||
2509 | // ************* | 3752 | // ************* | ||
2510 | // Disabling actions to be disabled at this point | 3753 | // Disabling actions to be disabled at this point | ||
2511 | // ************* | 3754 | // ************* | ||
2512 | { | 3755 | { | ||
Show All 9 Lines | |||||
2522 | // Disabling actions based on conditions | 3765 | // Disabling actions based on conditions | ||
2523 | // ************* | 3766 | // ************* | ||
2524 | { | 3767 | { | ||
2525 | QString tooltip = i18n("Create a new transaction"); | 3768 | QString tooltip = i18n("Create a new transaction"); | ||
2526 | const QVector<QPair<Action, bool>> actionStates { | 3769 | const QVector<QPair<Action, bool>> actionStates { | ||
2527 | // {qMakePair(Action::FileOpenDatabase, true)}, | 3770 | // {qMakePair(Action::FileOpenDatabase, true)}, | ||
2528 | // {qMakePair(Action::FileSaveAsDatabase, fileOpen)}, | 3771 | // {qMakePair(Action::FileSaveAsDatabase, fileOpen)}, | ||
2529 | {qMakePair(Action::FilePersonalData, fileOpen)}, | 3772 | {qMakePair(Action::FilePersonalData, fileOpen)}, | ||
2530 | {qMakePair(Action::FileBackup, (fileOpen && !d->m_myMoneyView->isDatabase()))}, | 3773 | {qMakePair(Action::FileBackup, (fileOpen && !isDatabase()))}, | ||
2531 | {qMakePair(Action::FileInformation, fileOpen)}, | 3774 | {qMakePair(Action::FileInformation, fileOpen)}, | ||
2532 | {qMakePair(Action::FileImportTemplate, fileOpen/* && !importRunning*/)}, | 3775 | {qMakePair(Action::FileImportTemplate, fileOpen/* && !importRunning*/)}, | ||
2533 | {qMakePair(Action::FileExportTemplate, fileOpen/* && !importRunning*/)}, | 3776 | {qMakePair(Action::FileExportTemplate, fileOpen/* && !importRunning*/)}, | ||
2534 | #ifdef KMM_DEBUG | 3777 | #ifdef KMM_DEBUG | ||
2535 | {qMakePair(Action::FileDump, fileOpen)}, | 3778 | {qMakePair(Action::FileDump, fileOpen)}, | ||
2536 | #endif | 3779 | #endif | ||
2537 | {qMakePair(Action::EditFindTransaction, fileOpen)}, | 3780 | {qMakePair(Action::EditFindTransaction, fileOpen)}, | ||
2538 | {qMakePair(Action::ToolCurrencies, fileOpen)}, | 3781 | {qMakePair(Action::ToolCurrencies, fileOpen)}, | ||
▲ Show 20 Lines • Show All 381 Lines • ▼ Show 20 Line(s) | 4160 | while (!d->m_importUrlsQueue.isEmpty()) { | |||
2920 | QString url = d->m_importUrlsQueue.head(); | 4163 | QString url = d->m_importUrlsQueue.head(); | ||
2921 | 4164 | | |||
2922 | // Bring this window to the forefront. This method was suggested by | 4165 | // Bring this window to the forefront. This method was suggested by | ||
2923 | // Lubos Lunak <l.lunak@suse.cz> of the KDE core development team. | 4166 | // Lubos Lunak <l.lunak@suse.cz> of the KDE core development team. | ||
2924 | // TODO: port KF5 (WebConnect) | 4167 | // TODO: port KF5 (WebConnect) | ||
2925 | //KStartupInfo::setNewStartupId(this, asn_id); | 4168 | //KStartupInfo::setNewStartupId(this, asn_id); | ||
2926 | 4169 | | |||
2927 | // Make sure we have an open file | 4170 | // Make sure we have an open file | ||
2928 | if (! d->m_myMoneyView->fileOpen() && | 4171 | if (! d->m_fileOpen && | ||
2929 | KMessageBox::warningContinueCancel(kmymoney, i18n("You must first select a KMyMoney file before you can import a statement.")) == KMessageBox::Continue) | 4172 | KMessageBox::warningContinueCancel(kmymoney, i18n("You must first select a KMyMoney file before you can import a statement.")) == KMessageBox::Continue) | ||
2930 | kmymoney->slotFileOpen(); | 4173 | kmymoney->slotFileOpen(); | ||
2931 | 4174 | | |||
2932 | // only continue if the user really did open a file. | 4175 | // only continue if the user really did open a file. | ||
2933 | if (d->m_myMoneyView->fileOpen()) { | 4176 | if (d->m_fileOpen) { | ||
2934 | KMSTATUS(i18n("Importing a statement via Web Connect")); | 4177 | KMSTATUS(i18n("Importing a statement via Web Connect")); | ||
2935 | 4178 | | |||
2936 | // remove the statement files | 4179 | // remove the statement files | ||
2937 | d->unlinkStatementXML(); | 4180 | d->unlinkStatementXML(); | ||
2938 | 4181 | | |||
2939 | QMap<QString, KMyMoneyPlugin::ImporterPlugin*>::const_iterator it_plugin = d->m_plugins.importer.constBegin(); | 4182 | QMap<QString, KMyMoneyPlugin::ImporterPlugin*>::const_iterator it_plugin = d->m_plugins.importer.constBegin(); | ||
2940 | while (it_plugin != d->m_plugins.importer.constEnd()) { | 4183 | while (it_plugin != d->m_plugins.importer.constEnd()) { | ||
2941 | if ((*it_plugin)->isMyFormat(url)) { | 4184 | if ((*it_plugin)->isMyFormat(url)) { | ||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Line(s) | 4228 | { | |||
2986 | if (!d->m_inAutoSaving) { | 4229 | if (!d->m_inAutoSaving) { | ||
2987 | // store the focus widget so we can restore it after save | 4230 | // store the focus widget so we can restore it after save | ||
2988 | QPointer<QWidget> focusWidget = qApp->focusWidget(); | 4231 | QPointer<QWidget> focusWidget = qApp->focusWidget(); | ||
2989 | d->m_inAutoSaving = true; | 4232 | d->m_inAutoSaving = true; | ||
2990 | KMSTATUS(i18n("Auto saving...")); | 4233 | KMSTATUS(i18n("Auto saving...")); | ||
2991 | 4234 | | |||
2992 | //calls slotFileSave if needed, and restart the timer | 4235 | //calls slotFileSave if needed, and restart the timer | ||
2993 | //it the file is not saved, reinitializes the countdown. | 4236 | //it the file is not saved, reinitializes the countdown. | ||
2994 | if (d->m_myMoneyView->dirty() && d->m_autoSaveEnabled) { | 4237 | if (d->dirty() && d->m_autoSaveEnabled) { | ||
2995 | if (!slotFileSave() && d->m_autoSavePeriod > 0) { | 4238 | if (!slotFileSave() && d->m_autoSavePeriod > 0) { | ||
2996 | d->m_autoSaveTimer->setSingleShot(true); | 4239 | d->m_autoSaveTimer->setSingleShot(true); | ||
2997 | d->m_autoSaveTimer->start(d->m_autoSavePeriod * 60 * 1000); | 4240 | d->m_autoSaveTimer->start(d->m_autoSavePeriod * 60 * 1000); | ||
2998 | } | 4241 | } | ||
2999 | } | 4242 | } | ||
3000 | 4243 | | |||
3001 | d->m_inAutoSaving = false; | 4244 | d->m_inAutoSaving = false; | ||
3002 | if (focusWidget && focusWidget != qApp->focusWidget()) { | 4245 | if (focusWidget && focusWidget != qApp->focusWidget()) { | ||
▲ Show 20 Lines • Show All 311 Lines • ▼ Show 20 Line(s) | 4553 | { | |||
3314 | q->d->m_myMoneyView->slotObjectSelected(MyMoneySchedule()); | 4557 | q->d->m_myMoneyView->slotObjectSelected(MyMoneySchedule()); | ||
3315 | q->d->m_myMoneyView->slotObjectSelected(MyMoneyTag()); | 4558 | q->d->m_myMoneyView->slotObjectSelected(MyMoneyTag()); | ||
3316 | q->d->m_myMoneyView->slotTransactionsSelected(KMyMoneyRegister::SelectedTransactions()); | 4559 | q->d->m_myMoneyView->slotTransactionsSelected(KMyMoneyRegister::SelectedTransactions()); | ||
3317 | // q->slotSelectTransactions(KMyMoneyRegister::SelectedTransactions()); | 4560 | // q->slotSelectTransactions(KMyMoneyRegister::SelectedTransactions()); | ||
3318 | 4561 | | |||
3319 | m_reconciliationAccount = MyMoneyAccount(); | 4562 | m_reconciliationAccount = MyMoneyAccount(); | ||
3320 | m_myMoneyView->finishReconciliation(MyMoneyAccount()); | 4563 | m_myMoneyView->finishReconciliation(MyMoneyAccount()); | ||
3321 | 4564 | | |||
3322 | m_myMoneyView->closeFile(); | 4565 | m_myMoneyView->slotFileClosed(); | ||
4566 | | ||||
4567 | disconnectStorageFromModels(); | ||||
4568 | | ||||
4569 | // notify the models that the file is going to be closed (we should have something like dataChanged that reaches the models first) | ||||
4570 | Models::instance()->fileClosed(); | ||||
4571 | | ||||
4572 | emit q->kmmFilePlugin(KMyMoneyApp::preClose); | ||||
4573 | if (q->isDatabase()) | ||||
4574 | MyMoneyFile::instance()->storage()->close(); // to log off a database user | ||||
4575 | newStorage(); | ||||
4576 | | ||||
4577 | emit q->kmmFilePlugin(postClose); | ||||
4578 | m_fileOpen = false; | ||||
4579 | | ||||
3323 | m_fileName = QUrl(); | 4580 | m_fileName = QUrl(); | ||
3324 | q->updateCaption(); | 4581 | q->updateCaption(); | ||
3325 | 4582 | | |||
3326 | // just create a new balance warning object | 4583 | // just create a new balance warning object | ||
3327 | delete m_balanceWarning; | 4584 | delete m_balanceWarning; | ||
3328 | m_balanceWarning = new KBalanceWarning(q); | 4585 | m_balanceWarning = new KBalanceWarning(q); | ||
3329 | 4586 | | |||
3330 | emit q->fileLoaded(m_fileName); | 4587 | emit q->fileLoaded(m_fileName); | ||
3331 | } | 4588 | } |
Isn't
the same as
?